mongodb 解決吃記憶體問題

2021-09-04 02:42:53 字數 4888 閱讀 9820

本文就來剖析一下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:

檢視記憶體情況最常用的是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()

另外,通過調整核心引數drop_caches也可以釋放快取:

shell> sysctl -w vm.drop_caches=1

平時可以通過mongo命令列來監控mongodb的記憶體使用情況,如下所示:

mongo> db.serverstatus().mem:

還可以通過mongostat命令來監控mongodb的記憶體使用情況,如下所示:

shell> mongostat

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

其中記憶體相關欄位的含義是:

visze:占用的虛擬記憶體大小

res:實際使用的記憶體大小

注:如果操作不能再記憶體中完成,結果faults列的數值不會是0,視大小可能有效能問題。

如果想驗證這一點,可以在開啟或關閉journal後,通過pmap命令來觀察檔案對映情況:

shell> pmap $(pidof mongod)

到底mongodb配備多大記憶體合適?寬泛點來說,多多益善,如果要確切點來說,這實際取決於你的資料及索引的大小,記憶體如果能夠裝下全部資料加索引是最佳情況,不過很多時候,資料都會比記憶體大,比如本文說涉及的mongodb例項:

mongo> db.stats()

本例中索引只有1g多,記憶體完全能裝下,而資料檔案則達到了1t,估計很難找到這麼大記憶體,此時保證記憶體能裝下熱資料即可,至於熱資料有多少,這就是個比例問題了,取決於具體的應用。如此一來記憶體大小就明確了:記憶體 > 索引 + 熱資料。

根據以上的分析我們可以得出幾點結論:

1. mongodb 直接用作業系統的記憶體管理器來管理記憶體。而作業系統採用的是lru演算法淘汰冷資料。

2. mongodb可以用重啟服務、調整核心引數以及mongodb內部的語法去清理mongodb對記憶體的快取。可能存在的問題是:這幾種清理方式都是全部清理,這樣的話mongodb的記憶體快取就失效了。

3. mongodb 對記憶體的使用是可以被監控的,在生產環境中要定時的去監控這些資料。

4. mongodb 對記憶體這種占用方式使其盡量的和其他占用記憶體的業務分開部署,例如memcahe,sphinx,mysql等。

5. 作業系統中的交換分割槽swap 如果操作頻繁的話,會嚴重降低系統效率。要解決可以禁用交換分割槽,以及增加記憶體以及做分布式。

6. 生產環境中mongodb所在的主機應該盡量的大記憶體。

Mongo資料庫吃記憶體問題以及解決情況

最近一直跑得好好的專案總是會莫名其妙的停了服務,最初的時候沒有在意這個情況,覺得可能只是乙個意外而已,可連著發生了好幾次,就覺得有點怪異了,然後檢視tomcat的log檔案,就發現了問題所在了,記憶體不足 當時還覺得有點不理解,應該這台伺服器的配置還是很高的,然後伺服器上也只是跑了兩個tomcat和...

解決 記憶體出錯問題

tianweishuiguo的回答 char a this is 這個在常量區分配乙個空間,然後a指向此空間 char a this is 這個在常量區分配乙個空間,然後又在棧上分配乙個空間,將常量區的內容複製過來,所以可以修改 解決方法 strcat t,p 這樣寫是不對的,t是字元型變數,而st...

解決記憶體洩漏問題

編譯 執行下列程式後。從輸出結果發現沒有呼叫 class y 的析構函式,出現了記憶體洩漏。請嘗試修改class x類的定 決這個記憶體洩露問題。並提交定義class x類的 class x x private int p include using namespace std 你提交的 將嵌入到這...