目前,MongoDB使用的是內存映射存儲引擎,它會把磁盤IO操作轉換成內存操作,如果是讀操作,內存中的數據起到緩存的作用,如果是寫操作,內存還可以把隨機的寫操作轉換成順序的寫操作,總之可以大幅度提升性能。MongoDB並不干涉內存管理工作,而是把這些工作留給操作系統的虛擬緩存管理器去處理,這樣的好處是簡化了MongoDB的工作,但壞處是你沒有方法很方便的控制MongoDB占多大內存,事實上MongoDB會占用所有能用的內存,所以最好不要把別的服務和MongoDB放一起。
有時候,即便MongoDB使用的是64位操作系統,也可能會遭遇臭名昭著的OOM問題,出現這種情況,多半是因為限制了虛擬內存的大小所致,可以這樣查看當前值:
[root@localhost bin]# ulimit -a | grep 'virtual' virtual memory (kbytes, -v) unlimited
多數操作系統缺省都是把它設置成unlimited的,如果你的操作系統不是,可以這樣修改:
[root@localhost bin]# ulimit -v unlimited [root@localhost bin]#
不過要注意的是,ulimit的使用是有上下文的,最好放在MongoDB的啟動腳本里。
另外,通過調整內核參數drop_caches也可以釋放緩存:
[root@localhost bin]# sysctl -w vm.drop_caches=1 vm.drop_caches = 1
平時可以通過mongo命令行來監控MongoDB的內存使用情況,如下所示:
repl:PRIMARY> db.serverStatus().mem { "bits" : 64, "resident" : 82, "virtual" : 5316, "supported" : true, "mapped" : 2287, "mappedWithJournal" : 4574 }
還可以通過mongostat命令來監控MongoDB的內存使用情況,如下所示:
[root@localhost bin]# ./mongostat
mapped vsize res faults 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0 4.2G 9.2G 84.0M 0
其中內存相關字段的含義是:
mapped:映射到內存的數據大小
visze:占用的虛擬內存大小
res:實際使用的內存大小
注:如果操作不能再內存中完成,結果faults列的數值不會是0,視大小可能有性能問題。
在上面的結果中,vsize是mapped的兩倍,而mapped等於數據文件的大小,所以說vsize是數據文件的兩倍,之所以會這樣,是因為本例中,MongoDB開啟了journal,需要在內存里多映射一次數據文件,如果關閉journal,則vsize和mapped大致相當。
如果想驗證這一點,可以在開啟或關閉journal后,通過pmap命令來觀察文件映射情況:
[root@localhost bin]# pmap $(pidof mongod) 19300: ./mongod --config /root/software/mongodb/mongo.conf 0000000000400000 20396K r-x-- /root/software/mongodb/bin/mongod 00000000019ea000 560K rw--- /root/software/mongodb/bin/mongod
到底MongoDB配備多大內存合適?寬泛點來說,多多益善,如果要確切點來說,這實際取決於你的數據及索引的大小,內存如果能夠裝下全部數據加索引是最佳情況,不過很多時候,數據都會比內存大,比如本文說涉及的MongoDB實例:
repl:PRIMARY> db.stats() { "db" : "admin", "collections" : 0, "objects" : 0, "avgObjSize" : 0, "dataSize" : 0, "storageSize" : 0, "numExtents" : 0, "indexes" : 0, "indexSize" : 0, "fileSize" : 0, "ok" : 1 }
另外實例:
mongo> db.stats() { "dataSize" : 1004862191980, "indexSize" : 1335929664 }
本例中索引只有1G多,內存完全能裝下,而數據文件則達到了1T,估計很難找到這么大內存,此時保證內存能裝下熱數據即可,至於熱數據有多少,這就是個比例問題了,取決於具體的應用。如此一來內存大小就明確了:內存 > 索引 + 熱數據。
關於MongoDB與內存的話題,大家還可以參考官方文檔中的相關介紹。