上一篇:Mongodb VS Mysql 查詢性能,測試了 mongodb 與 mysql 的查詢性能。結果說明 mongodb 性能可以, 可以代替 mysql 來使用。
但是這個測試都是在百萬級別,我的場景在 KW 級別。所以還要對 mongodb 在 kw 級別下測試效果。
我測試環境是 4G 內存(有好些內存被其它程序占用),2kw 數據,查詢隨機生成 id(一次查詢 20 個id)。
在這樣的環境中測試不理想,比較失望。平均一次查詢 500ms(比 mysql 還差,特別是在并發查詢下,性能較差。很底的吞吐量)。查看其索引大小(用 db.mycoll.stats() 可以查詢):2kw 數據中有 1.1G 左右的索引,存儲的數據在 11G 左右。
測試過程中發現 iowait 占 50% 左右,看來還是 io 的瓶頸。還看到 mongodb 使用的內存不多(小于索引的大小,看來這機器不足夠來測試)。
換了個有可用 6G 內存的機器。在 50 個并發下,可以達到平均 100 ms 左右,算比較滿意,但是并發好像能力不夠強。但這個性能不能由我控制,還由機器的可用內存控制。原因就是 mongodb 沒有指定可占用的內存大小,它把所有空閑內存當緩存使用,既是優點也是缺點:優點--可以最大限度提升性能;缺點--容易受其它程序干擾(占用了它的緩存)。由我測試來看,它搶占內存的能力不強。mongodb 是用內存映射文件 vmm,官方的說明:
Memory Mapped Storage Engine
This is the current storage engine for MongoDB, and it uses memory-mapped files for all disk I/O. Using this strategy, the operating system's virtual memory manager is in charge of caching. This has several implications:
There is no redundancy between file system cache and database cache: they are one and the same.
MongoDB can use all free memory on the server for cache space automatically without any configuration of a cache size.
Virtual memory size and resident size will appear to be very large for the mongod process. This is benign: virtual memory space will be just larger than the size of the datafiles open and mapped; resident size will vary depending on the amount of memory not used by other processes on the machine.
Caching behavior (such as LRU'ing out of pages, and laziness of page writes) is controlled by the operating system: quality of the VMM implementation will vary by OS.
所以這么來看,我覺得 mongodb 沒有指定內存大小來保證正常的緩存是個缺點。應該至少保證索引全部能放到內存中。但這個行為不是由啟動程序決定,而是由環境決定(美中不足)。
官方也有段內容說到索引放到內存中:
If your queries seem sluggish, you should verify that your indexes are small enough to fit in RAM. For instance, if you're running on 4GB RAM and you have 3GB of indexes, then your indexes probably aren't fitting in RAM. You may need to add RAM and/or verify that all the indexes you've created are actually being used.
還是希望 mongodb 中可以指定內存大小,確保它有足夠內存加載索引。
小結:大數據量下(kw級)mongodb 并發查詢不夠理想(100-200/s)。寫數據很快(我的環境,遠程提交近 1w/s,估計達到 1.5W/s 是沒問題的,基本不受大數據量的影響)。
貼個測試數據:
1 id(內存使用 <1.5g) 10 id(內存使用 2-3g) 20 id(內存使用 >4g)
1 2 3 1 2 3 1 2 3
total time 17.136 25.508 17.387 37.138 33.788 25.143 44.75 31.167 30.678
1 thread thruput 583.5668 392.0339 575.1423 269.266 295.9631 397.725 223.4637 320.8522 325.9665
total time 24.405 22.664 24.115 41.454 41.889 39.749 56.138 53.713 54.666
5 thread thruput 2048.76 2206.142 2073.398 1206.156 1193.631 1257.893 890.6623 930.8733 914.6453
total time 27.567 26.867 28.349 55.672 54.347 50.93 72.978 81.857 75.925
10 thread thruput 3627.526 3722.038 3527.461 1796.235 1840.028 1963.479 1370.276 1221.643 1317.089
total time 51.397 57.446 53.81 119.386 118.015 76.405 188.962 188.034 138.839
20 thread thruput 3891.278 3481.53 3716.781 1675.238 1694.7 2617.63 1058.414 1063.637 1440.517
total time 160.038 160.808 160.346 343.559 352.732 460.678 610.907 609.986 1411.306
50 thread thruput 3124.258 3109.298 3118.257 1455.354 1417.507 1085.357 818.4552 819.6909 354.2818
total time 2165.408 635.887 592.958 1090.264 1034.057 1060.266 1432.296 1466.971 1475.061
100 thread thruput 461.8067 1572.606 1686.46 917.209 967.0647 943.1595 698.1797 681.6767 677.9381
上面的測試分別用三種查詢(每次 1,10,20 id),在不同并發下測試3次,每次發出 1w 次查詢。第一行數據為所有線程累加時間(單位 ms),第二行數據為吞吐量(1w /(total time / thread num))。測試中內存使用慢慢增加,所以后面的數據可能比較高效的(高效的環境)。
從上表看,10 - 20線程比較高的吞吐量。看到內存使用,前提就是索引加載到內存中,并有些內存作為緩存。
下面有個索引查詢優化的 pdf。
Indexing and Query Optimizer
Indexing and Query Optimizer (Aaron Staple)
ps:
默認 mongodb 服務器只有10個并發,如果要提高它的連接數,可以用 --maxConns num 來提高它的接收并發的數據。
mongodb 的 java 驅動默認最多只有 10 并發連接池。要提高它,可以在 mongo.jar 的環境中加入 MONGO.POOLSIZE 系統參數,如 java -DMONGO.POOLSIZE=50 ...