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 直接用作業系統的記憶體管理器來管理記憶體。而作業系統採用的是演算法淘汰冷資料。
2. mongodb可以用重啟服務、調整核心引數以及mongodb內部的語法去清理mongodb對記憶體的快取。可能存在的問題是:這幾種清理方式都是全部清理,這樣的話mongodb的記憶體快取就失效了。
3. mongodb 對記憶體的使用是可以被監控的,在生產環境中要定時的去監控這些資料。
4. mongodb 對記憶體這種佔用方式使其儘量的和其他佔用記憶體的業務分開部署,例如memcahe,sphinx,mysql等。
5. 作業系統中的交換分割槽swap 如果操作頻繁的話,會嚴重降低系統效率。要解決可以禁用交換分割槽,以及增加記憶體以及做分散式。
6. 生產環境中mongodb所在的主機應該儘量的大記憶體。
該文章轉自洪荒聽雨的部落格。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15498/viewspace-1870420/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mongodb 對記憶體的嚴重佔用以及解決方法MongoDB記憶體
- mysql佔用記憶體高的一種解決方法MySql記憶體
- win10記憶體佔用高解決方法Win10記憶體
- weblogic記憶體佔用等問題的解決方法Web記憶體
- 電腦記憶體佔用過高怎麼辦 電腦記憶體佔用過高解決方法記憶體
- SQL Server資料庫佔用記憶體過多的解決方法SQLServer資料庫記憶體
- 解決Apache長時間佔用記憶體大的問題,Apache 記憶體優化方法Apache記憶體優化
- win10記憶體佔用高怎麼解決_win10系統記憶體佔用高解決步驟Win10記憶體
- mongodb記憶體不足怎麼解決?MongoDB記憶體
- win10開機記憶體佔用高怎麼解決_win10開機後記憶體佔用高的解決措施Win10記憶體
- filebeat實踐-記憶體佔用-最大記憶體佔用記憶體
- win10開機記憶體佔用60%怎麼辦 解決開機執行記憶體佔用率過高的方法Win10記憶體
- win10 audiodg狂佔記憶體怎麼辦_win10 audiodg佔用記憶體過高的解決方法Win10記憶體
- C語言記憶體洩露很嚴重,如何應對?C語言記憶體洩露
- ubuntu解決GPU視訊記憶體佔用問題UbuntuGPU記憶體
- win10系統一開機記憶體就佔用50%的解決方法Win10記憶體
- [轉帖]Solaris記憶體管理以及判定記憶體是否夠用的方法記憶體
- win10卡頓嚴重怎麼解決 win10卡頓嚴重的解決方法Win10
- Win10記憶體佔用過多怎麼辦 win10清理記憶體佔用的方法Win10記憶體
- 實用乾貨,教你解決Chrome佔記憶體硬傷Chrome記憶體
- 解決XP單擊右鍵佔用大量記憶體(轉)記憶體
- win10大量的服務主機電腦記憶體佔用高解決方法Win10記憶體
- win10系統快速啟動佔用記憶體如何解決_win10快速啟動佔用記憶體高的解決教程Win10記憶體
- win10記憶體佔用率高怎麼解決 win10記憶體佔用率突然爆滿處理方法Win10記憶體
- 解決ORACLE共享記憶體不足的方法Oracle記憶體
- 修改oracle記憶體佔用Oracle記憶體
- 資源記憶體佔用記憶體
- 解決SQL Server資料庫佔用記憶體過多的問題SQLServer資料庫記憶體
- LINUX 佔用較多記憶體 解釋Linux記憶體
- python物件的記憶體佔用Python物件記憶體
- win10記憶體佔用過高程式沒多少怎麼辦 win10記憶體佔用過高的方法Win10記憶體
- win10怎麼關閉佔用記憶體的服務_win10關掉佔用記憶體服務方法Win10記憶體
- ECS記憶體佔用高導致wordpress資料庫經常掛掉的兩種解決方法記憶體資料庫
- node計算記憶體佔用記憶體
- 託管堆記憶體佔用記憶體
- influxdb記憶體佔用剖析UX記憶體
- 深度解讀昇騰CANN記憶體複用技術,降低網路記憶體佔用記憶體
- 為硬體保留記憶體 問題的解決方法記憶體