mongodb 對內存的嚴重佔用以及解決方法【轉載】

mongodb 對內存的嚴重佔用以及解決方法【轉載】 

剛開始使用mongodb的時候,不太注意mongodb的內存使用,但經過查資料發現mongodb對內存的佔用是巨大的,在本地測試服務器中,8G的內存竟然被佔用了45%。汗呀。 
本文就來剖析一下mongodb對內存的具體使用方法,以及生產環境針對mongodb佔大量內存的問題的解決。 
先看一個MongoDB服務器的top命令結果 
shell> top -p $(pidof mongod) 
Mem:  32872124k total, 30065320k used,  2806804k free,   245020k buffers 
Swap:  2097144k total,      100k used,  2097044k free, 26482048k cached 
VIRT  RES  SHR %MEM 
1892g  21g  21g 69.6 

或者 先top後,而後 shift+m 把當前進場按佔用內存的多少排序。看看你的mongodb能佔用多少內存。 


先了解一下linux對內存的管理方式: 
在Linux裏(別的系統也差很少),內存有物理內存和虛擬內存之說,物理內存是什麼天然無需解釋,虛擬內存實際是物理內存的抽象,多數狀況下,出於方便性的考慮,程序訪問的都是虛擬內存地址,而後操做系統會把它翻譯成物理內存地址。 
不少人會把虛擬內存和Swap混爲一談,實際上Swap只是虛擬內存引伸出的一種技術而已:操做系統一旦物理內存不足,爲了騰出內存空間存放新內容,就會把當前物理內存中的內容放到交換分區裏,稍後用到的時候再取回來,須要注意的是,Swap的使用可能會帶來性能問題,偶爾爲之無需緊張,糟糕的是物理內存和交換分區頻繁的發生數據交換,這被稱之爲Swap顛簸,一旦發生這種狀況,先要明確是什麼緣由形成的,若是是內存不足就好辦了,加內存就能夠解決,不過有的時候即便內存充足也可能會出現這種問題,好比MySQL就有可能出現這樣的狀況,解決方法是限制使用Swap: 
shell> sysctl -w vm.swappiness=0 
查看內存狀況最經常使用的是free命令: 
shell> free -m 
             total       used       free     shared    buffers     cached 
Mem:         32101      29377       2723          0        239      25880 
-/+ buffers/cache:       3258      28842 
Swap:         2047          0       2047 
新手看到used一欄數值偏大,free一欄數值偏小,每每會認爲內存要用光了。其實並不是如此,之因此這樣是由於每當咱們操做文件的時候,Linux都會盡量的把文件緩存到內存裏,這樣下次訪問的時候,就能夠直接從內存中取結果,因此cached一欄的數值很是的大,不過不用擔憂,這部份內存是可回收的,操做系統會按照LRU算法淘汰冷數據。除了cached,還有一個buffers,它和cached相似,也是可回收的,不過它的側重點在於緩解不一樣設備的操做速度不一致形成的阻塞,這裏就很少作解釋了。 
知道了原理,咱們就能夠推算出系統可用的內存是free + buffers + cached: 
shell> echo "2723 + 239 + 25880" | bc -l 
28842 
至於系統實際使用的內存是used – buffers – cached: 
shell> echo "29377 - 239 - 25880" | bc -l 
3258 
除了free命令,還可使用sar命令: 
shell> sar -r 
kbmemfree kbmemused  %memused kbbuffers  kbcached 
  3224392  29647732     90.19    246116  26070160 
  3116324  29755800     90.52    245992  26157372 
  2959520  29912604     91.00    245556  26316396 
  2792248  30079876     91.51    245680  26485672 
  2718260  30153864     91.73    245684  26563540 

shell> sar -W 
pswpin/s pswpout/s 
    0.00      0.00 
    0.00      0.00 
    0.00      0.00 
    0.00      0.00 
    0.00      0.00 
但願你沒有被%memused嚇到,若是不幸言中,請參考free命令的解釋。 

接着我們分析一下mongodb是怎麼使用內存的: 

目前,MongoDB使用的是內存映射存儲引擎,它會把磁盤IO操做轉換成內存操做,若是是讀操做,內存中的數據起到緩存的做用,若是是寫操做,內存還能夠把隨機的寫操做轉換成順序的寫操做,總之能夠大幅度提高性能。MongoDB並不干涉內存管理工做,而是把這些工做留給操做系統的虛擬緩存管理器去處理,這樣的好處是簡化了MongoDB的工做,但壞處是你沒有方法很方便的控制MongoDB佔多大內存,事實上MongoDB會佔用全部能用的內存,因此最好不要把別的服務和MongoDB放一塊兒。 

有時候,即使MongoDB使用的是64位操做系統,也可能會遭遇臭名昭著的OOM問題,出現這種狀況,多半是由於限制了虛擬內存的大小所致,能夠這樣查看當前值: 

shell> ulimit -a | grep 'virtual' 
多數操做系統缺省都是把它設置成unlimited的,若是你的操做系統不是,能夠這樣修改: 

shell> ulimit -v unlimited 
不過要注意的是,ulimit的使用是有上下文的,最好放在MongoDB的啓動腳本里。 

有時候,出於某些緣由,你可能想釋放掉MongoDB佔用的內存,不過前面說了,內存管理工做是由虛擬內存管理器控制的,因此一般你只能經過重啓服務來釋放內存,你必定不齒於這樣的方法,幸虧可使用MongoDB內置的closeAllDatabases命令達到目的: 

mongo> use admin 
mongo> db.runCommand({closeAllDatabases:1}) 
另外,經過調整內核參數drop_caches也能夠釋放緩存: 

shell> sysctl -w vm.drop_caches=1 
平時能夠經過mongo命令行來監控MongoDB的內存使用狀況,以下所示: 

mongo> db.serverStatus().mem: 

    "resident" : 22346, 
    "virtual" : 1938524, 
    "mapped" : 962283 

還能夠經過mongostat命令來監控MongoDB的內存使用狀況,以下所示: 
shell> mongostat 
mapped  vsize    res faults 
  940g  1893g  21.9g      0 
  940g  1893g  21.9g      0 
  940g  1893g  21.9g      0 
  940g  1893g  21.9g      0 
  940g  1893g  21.9g      0 

其中內存相關字段的含義是: 
mapped:映射到內存的數據大小 
visze:佔用的虛擬內存大小 
res:實際使用的內存大小 
注:若是操做不能再內存中完成,結果faults列的數值不會是0,視大小可能有性能問題。 

在上面的結果中,vsize是mapped的兩倍,而mapped等於數據文件的大小,因此說vsize是數據文件的兩倍,之因此會這樣,是由於本例中,MongoDB開啓了journal,須要在內存裏多映射一次數據文件,若是關閉journal,則vsize和mapped大體至關。 

若是想驗證這一點,能夠在開啓或關閉journal後,經過pmap命令來觀察文件映射狀況: 
shell> pmap $(pidof mongod) 
到底MongoDB配備多大內存合適?寬泛點來講,多多益善,若是要確切點來講,這實際取決於你的數據及索引的大小,內存若是可以裝下所有數據加索引是最佳狀況,不過不少時候,數據都會比內存大,好比本文說涉及的MongoDB實例: 
mongo> db.stats() 

        "dataSize" : 1004862191980, 
        "indexSize" : 1335929664 

本例中索引只有1G多,內存徹底能裝下,而數據文件則達到了1T,估計很難找到這麼大內存,此時保證內存能裝下熱數據便可,至於熱數據有多少,這就是個比例問題了,取決於具體的應用。如此一來內存大小就明確了:內存 > 索引 + 熱數據。 

根據以上的分析咱們能夠得出幾點結論: 
1. mongodb 直接用操做系統的內存管理器來管理內存。而操做系統採用的是LRU算法淘汰冷數據。 
2. mongodb能夠用重啓服務、調整內核參數以及mongodb內部的語法去清理mongodb對內存的緩存。可能存在的問題是:這幾種清理方式都是所有清理,這樣的話mongodb的內存緩存就失效了。 
3. mongodb 對內存的使用是能夠被監控的,在生產環境中要定時的去監控這些數據。 
4. mongodb 對內存這種佔用方式使其儘可能的和其餘佔用內存的業務分開部署,例如memcahe,sphinx,mysql等。 
5. 操做系統中的交換分區swap 若是操做頻繁的話,會嚴重下降系統效率。要解決能夠禁用交換分區,以及增長內存以及作分佈式。 
6.  生產環境中mongodb所在的主機應該儘可能的大內存。 mysql

相關文章
相關標籤/搜索