mongodb

點擊打開鏈接



overview

     MongoDB使用的是內存映射存儲引擎,即Memory Mapped Storage Engine,簡稱MMAP。MMAP可以把磁盤文件的一部分或全部內容直接映射到內存,這樣文件中的信息位置就會在內存中有對應的地址空間,這時對文件的讀寫可以直接用指針來做,而不需要read/write函數了,但這並不代表將文件map到物理內存,只有訪問到這塊數據時纔會被操作系統以Page的方式換到物理內存。MongoDB將內存管理工作交給操作系統的虛擬內存管理器來完成,這樣就大大簡化了MongoDB的工作,同時操作系統會將數據刷新保存到磁盤上,下圖就是MMAP的簡要工作原理圖







內存使用情況

查看Linux虛擬內存管理器是否對內存做了限制,如果顯示爲unlimited表示無限制

[jiangjianjian@f1-mongo1 ~]$  ulimit -a | grep memory 
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
virtual memory          (kbytes, -v) unlimited

修改虛擬內存限制

[jiangjianjian@f1-mongo1 ~]$ ulimit -m unlimited
[jiangjianjian@f1-mongo1 ~]$ ulimit -v unlimited

查看當前MongoDB的連接數

mongo中每一個連接都是一個線程,需要一個stack,從結果中可看到當前連接數爲2372,最大連接數爲51200
bj1-farm1:PRIMARY> db.serverStatus().connections
{
"current" : 2372,
"available" : 48828,
"totalCreated" : NumberLong(185449264)
}

Linux下缺省的Stack大小查看 

[jiangjianjian@f1-mongo1 ~]$ ulimit -a | grep stack
stack size              (kbytes, -s) 10240

MongoDB實際使用的Stack大小查看

可以用如下命令確認(單位:K)
[root@f1-mongo1 journal]# cat /proc/$(pidof mongod)/limits | grep stack | awk -F 'size' '{print int($NF)/1024}' 
10240 

調整stack大小的方法

如果Stack過大,比如上述的10240K,我們可以通過以下命令調整stack大小
[root@f1-mongo1 journal]#  ulimit -s 1024

MongoDB釋放內存的命令

mongo> use admin
mongo> db.runCommand({closeAllDatabases:1}) 
 

Mongodb自帶命令查看其內存使用情況

其中resident代表物理內存使用情況,單位爲M;而virtual爲虛擬內存使用情況,mapped是映射到內存的數據大小。這裏虛擬內存是mapped的兩倍,是因爲我們開啓了Journal日誌,需要在內存中多映射一次,大概就是它的兩倍了。如果關閉Journal日誌,虛擬內存大小將和mapped大小相當。
bj1-farm1:PRIMARY> db.serverStatus().mem
{
"bits" : 64,
"resident" : 46662,
"virtual" : 326198,
"supported" : true,
"mapped" : 161399,
"mappedWithJournal" : 322798
}

top命令查看

這裏還可以通過top命令觀察mongodb的內存使用情況,如下圖,可看到其中的VIRT和RES與上述命令的結果一樣
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                    
12603 mongod    20   0  318g  45g  44g S 28.0 72.1  27230:21 mongod 

free命令查看

而再通過free命令可查看到內存佔用中有多少是因爲數據緩存和cache,關於如何查看free命令,參見http://blog.csdn.net/cug_jiang126com/article/details/42266653
[jiangjianjian@f1-mongo1 ~]$ free
             total       used       free     shared    buffers     cached
Mem:      65921032   65262376     658656          0     274264   61742808
-/+ buffers/cache:    3245304   62675728
Swap:    100663288      11884  100651404

Mongodb內存大小配置建議

MongoDB應該分配的內存大小最好滿足內存大小>索引+熱數據+連接佔用內存,通過db.stats()命令可查看到當前數據庫的索引大小情況
bj1-farm1:PRIMARY> db.stats()
{
"db" : "yc_driver",                  //當前數據庫
"collections" : 5,                   //當前數據庫多少表
"objects" : 2911281,                //當前數據庫所有表多少條數據 
"avgObjSize" : 240.28991086741541,  //每條數據的平均大小
"dataSize" : 699551452,            //所有數據的總大小
"storageSize" : 858513408,          //所有數據佔的磁盤大小
"numExtents" : 21,                 
"indexes" : 5,                     //索引數
"indexSize" : 569229472,          //索引大小
"fileSize" : 2080374784,         //預分配給數據庫的文件大小
"nsSizeMB" : 16,
"dataFileVersion" : {
"major" : 4,
"minor" : 5
},
"extentFreeList" : {
"num" : 0,
"totalSize" : 0
},
"ok" : 1
}

參考文獻



點擊打開鏈接

目前,MongoDB使用的是內存映射存儲引擎,它會把數據文件映射到內存中,如果是讀操作,內存中的數據起到緩存的作用,如果是寫操 

作,內存還可以把隨機的寫操作轉換成順序的寫操作,總之可以大幅度提升性能。MongoDB並不干涉內存管理工作,而是把這些工作留給操 

作系統的虛擬內存管理器去處理,這樣做的好處是簡化了MongoDB的工作,但壞處是你沒有方法很方便的控制MongoDB佔多大內存,幸運 

的是虛擬內存管理器的存在讓我們多數時候並不需要關心這個問題。 

MongoDB的內存使用機制讓它在緩存重建方面更有優勢,簡而言之:如果重啓進程,那麼緩存依然有效,如果重啓系統,那麼可以通過拷貝 

數據文件到/dev/null的方式來重建緩存,更詳細的描述請參考:Cache Reheating – Not to be Ignored。 

有時候,即便MongoDB使用的是64位操作系統,也可能會遭遇OOM問題,出現這種情況,多半是因爲限制了內存的大小所致,可以這樣查 

看當前值: 

shell> ulimit -a | grep memory 
多數操作系統缺省都是把它設置成unlimited的,如果你的操作系統不是,可以這樣修改: 

shell> ulimit -m unlimitedshell> ulimit -v unlimited 
注:ulimit的使用是有上下文的,最好放在MongoDB的啓動腳本里。 

有時候,MongoDB連接數過多的話,會拖累性能,可以通過serverStatus查詢連接數: 

mongo> db.serverStatus().connections 
每個連接都是一個線程,需要一個Stack,Linux下缺省的Stack設置一般比較大: 

shell> ulimit -a | grep stackstack size              (kbytes, -s) 10240 
至於MongoDB實際使用的Stack大小,可以用如下命令確認(單位:K): 

shell> cat /proc/$(pidof mongod)/limits | grep stack | awk -F 'size' '{print int($NF)/1024}' 
如果Stack過大(比如:10240K)的話沒有意義,簡單對照命令結果中的Size和Rss: 

shell> cat /proc/$(pidof mongod)/smaps | grep 10240 -A 10 
所有連接消耗的內存加起來會相當驚人,推薦把Stack設置小一點,比如說1024: 

shell> ulimit -s 1024 
注:從開始,MongoDB會在啓動時自動設置Stack。 

有時候,出於某些原因,你可能想釋放掉MongoDB佔用的內存,不過前面說了,內存管理工作是由虛擬內存管理器控制的,幸好可以使用 

MongoDB內置的closeAllDatabases命令達到目的: 

mongo> use adminmongo> 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> mongostatmapped  vsize    res faults  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,估計很難找到這麼大內存,此時保證內存能裝下熱數據即可,至於熱數 

據是多少,取決於具體的應用。如此一來內存大小就明確了:內存 > 索引 + 熱數據,最好有點富餘,畢竟操作系統本身正常運轉也需要消耗一部分內存。 


發佈了52 篇原創文章 · 獲贊 23 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章