Mongodb

MongoDB 副本集主成員記憶體佔用高

  • December 31, 2017

我目前有一個分片集群啟動並執行,我注意到每個副本集的主要成員的記憶體使用率非常高,雖然我以以下方式啟動每個成員,但它是 8GB:

mongod --auth --bind_ip_all --shardsvr --replSet a --smallfiles --oplogSize 1024 --keyFile /file/somewhere/

我認為(可能天真地)這oplogSize會限制使用的記憶體量。

非常感謝任何有關如何解決此問題或突出我的方式錯誤的指導。

介紹

oplog與記憶體消耗無關。它是一個有上限的集合,用作一種預寫日誌,用於將操作複製到其他副本集成員。

一般來說,除非另有說明,否則 MongoDB 最多使用大約 85%(給予和獲取)的記憶體。此記憶體用於將索引和“工作集”(最近使用的文件的副本)保存在 RAM 中,以確保最佳性能。雖然在技術上可以限制 MongoDB 使用的 RAM,但這樣做是一個非常糟糕的主意™,因為您嚴重限制了 MongoDB 的性能,並且由於 RAM 不足而基本上無法檢測何時擴展或擴展。

TL;DR:如果你要問如何限制 MongoDB 使用的 RAM,你可能不應該限制它,因為你無法判斷這一步會引入的副作用。

限制 MongoDB 的記憶體消耗

你基本上有三個選擇:限制WiredTigers儲存引擎的記憶體大小,使用cgroups來限制可以從作業系統請求的記憶體或使用 Docker 這樣做(這使它更容易一些,但在引擎蓋下 Docker 也使用 cgroups , iirc)。mongod

選項 1:限制 WiredTigers 記憶體大小

將以下選項添加到您的配置文件(我假設它是 YAML 格式):

storage:
wiredTiger:
 engineConfig:
    cacheSizeGB: <number>

其中<number>是 MongoDB 允許用於 WiredTiger 記憶體的最大 RAM 量。請注意,擺弄此參數會嚴重影響性能(另一方面,總是會限制 MongoDB 的記憶體消耗)。另請注意,這並不限制其mongod自身使用的記憶體(例如,每個連接都分配了一個小堆棧)。

選項2:使用cgroups來限制整體記憶體消耗mongod

作為 root 使用者,首先確保 cgroups 已啟用:

$ lscgroup
cpuset:/
cpu:/
cpuacct:/
memory:/
devices:/
freezer:/
net_cls:/
blkio:/

假設 cgroups 可用,您現在可以為 MongoDB 的記憶體消耗配置一個控制組/etc/cgconfig.conf

group mongodb{
   memory {
       memory.limit_in_bytes = 512m;
   }
}

完成後,您需要重新啟動 cgconfig 服務。不要簡單地複制和粘貼上面的配置:使用 512 MB,MongoDB 將可以正常執行(如果有的話)。根據您的需要調整記憶體限制,至少 2GB 的 RAM。

接下來,您需要分配mongod給剛剛創建的控制組。為此,您需要編輯/etc/cgrules.conf

*:mongod memory mongodb/

where*表示該規則適用於誰啟動mongod,限制將根據控制組的規則應用於 RAM mongod/。作為最後一步,您現在需要重新啟動cgredMongoDB 服務。現在mongod應該只使用指定數量的 RAM,無論好壞。

選項 3:使用 Docker 來限制mongod的整體記憶體消耗:

  1. 確定您目前正在執行的 MongoDB 版本
$ mongod -version
db version v3.4.10
git version: 078f28920cb24de0dd479b5ea6c66c644f6326e9
OpenSSL version: OpenSSL 1.0.2n  7 Dec 2017
allocator: system
modules: none
build environment:
  distarch: x86_64
  target_arch: x86_64

您的輸出可能不同,但我們只需要db version,即次要版本。在本例中,它是“3.4”。 2. 拉取合適的 docker 鏡像

$ docker pull mongo:3.4

您應該為您之前確定的版本拉取 docker 鏡像,並在下一步中使用拉取的鏡像。 3. 使用適當的參數執行 docker 映像

$ docker run -d --name mongod --memory=512m \
> --mount type=bind,src=/path/to/your/datafiles,dst=/data/db \
> --mount type=bind,src=/file/somewhere/,dst=/key.file,readonly
> mongod <yourOptions>

這裡需要注意幾點:第一個mount使您現有的數據文件可以從容器內部訪問,而第二個mount對您的密鑰文件也是如此。您需要相應地調整您的 mongod 選項,即keyFile指向您將密鑰文件安裝到的目標的選項。有關詳細資訊,請參閱docker 文件mongo docker 映像的 README

結論

您有一個分片集群,並且您希望限制各個分片成員的記憶體消耗。

如果我們談論的是生產系統,這是一個非常糟糕的主意™:要麼您在執行您mongod的機器上執行其他服務(這將使這兩個服務在負載過重的情況下競爭資源),要麼人為地限制MongoDB 將提供的性能(通過使用上述方法)。這是糟糕的系統設計。你為什麼要分片?分片是 MongoDB 的負載平衡和橫向擴展方法(如果限制因素,例如 RAM,由於您獲得的收益不足而無法再縱向擴展)。我有一個口頭禪,我會向客戶重複(並且偶爾對自己說實話):

承載生產數據的 MongoDB 實例應在專用機器上執行。沒有例外!

根據您首先分片的原因以及您擁有的分片數量,如果您在專用機器上執行集群,您可能甚至不需要分片。算一算。

即使讓您的集群節點執行其他服務是一個好主意,它們顯然也沒有配置好。考慮到 RAM 的價格與降低的性能相比,使用相當數量的 RAM 來擴展您的機器基本上是不費吹灰之力的,而不是人為地限制它來強制執行一個糟糕的系統設計。

我對您的建議是不要遵循上述任何方法。相反,在專用機器上執行您的數據承載 MongoDB 實例。只要您在分片之前獲得相應的降壓 RAM 和 IO(CPU 很少成為問題),就可以擴大它們。在撰寫本文時,RAM 介於 128 和 256GB 之間,並且 RAID 0(如果你有一個副本集,你確實有,不是嗎?)或 RAID 10(如果你的分片不是副本集 - 你真丟臉 ;) ) 使用 SSD。僅當

  • 您的 IOPS 太多,單台機器無法處理
  • 您需要比您的副本集成員更多的 RAM,而且物有所值
  • 您擁有的數據多於一台機器可以保存的數據。

hth

PS 如果在限制 s 的 RAM 後性能下降,請不要將其歸咎於我或 MongoDB mongod

引用自:https://dba.stackexchange.com/questions/194157