mongodb記憶體管理

2021-06-07 19:57:08 字數 3798 閱讀 8955

但凡初次接觸mongodb的人,無不驚訝於它對記憶體的貪得無厭,至於個中緣由,我先講講linux是如何管理記憶體的,再說說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

在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使用的是記憶體對映儲存引擎,它會把磁碟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,估計很難找到這麼大記憶體,此時保證記憶體能裝下熱資料即可,至於熱資料有多少,這就是個比例問題了,取決於具體的應用。如此一來記憶體大小就明確了:記憶體 > 索引 + 熱資料。

關於mongodb與記憶體的話題,大家還可以參考官方文件中的相關介紹。

MongoDB與記憶體

但凡初次接觸mongodb的人,無不驚訝於它對記憶體的貪得無厭,至於個中緣由,我先講講linux是如何管理記憶體的,再說說mongodb是如何使用記憶體的,答案自然就清楚了。據說帶著問題學習更有效,那就先看乙個mongodb伺服器的top命令結果 shell top p pidof mongod m...

MONGODB記憶體溢位

最近遇到乙個mongodb記憶體溢位的故障 報錯資訊如下 登入mongodb伺服器,發現mongodb已經關閉 檢視mongodb log 2016 01 25t08 05 07.155 0800 conn250804 query rmid push 20161.record query plans...

MongoDB與記憶體

2011 08 19 但凡初次接觸mongodb的人,無不驚訝於它對記憶體的貪得無厭,至於個中緣由,我先講講linux是如何管理記憶體的,再說說mongodb是如何使用記憶體的,答案自然就清楚了。據說帶著問題學習更有效,那就先看乙個mongodb伺服器的top命令結果 shell top p pid...