MongoDB 副本集主成員記憶體佔用高
我目前有一個分片集群啟動並執行,我注意到每個副本集的主要成員的記憶體使用率非常高,雖然我以以下方式啟動每個成員,但它是 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
,限制將根據控制組的規則應用於 RAMmongod/
。作為最後一步,您現在需要重新啟動cgred
MongoDB 服務。現在mongod
應該只使用指定數量的 RAM,無論好壞。選項 3:使用 Docker 來限制
mongod
的整體記憶體消耗:
- 確定您目前正在執行的 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
。