MongoDB 使用太多記憶體
我們已經使用 MongoDB 幾個星期了,我們看到的總體趨勢是 mongodb 使用了太多的記憶體(遠遠超過其數據集 + 索引的整體大小)。
我已經通讀了這個問題和這個問題,但似乎都沒有解決我一直面臨的問題,他們實際上是在解釋文件中已經解釋的內容。
以下是htop和show dbs命令的結果。
我知道 mongodb 使用記憶體映射 IO,所以基本上作業系統會處理記憶體中的記憶體內容,並且 mongodb理論上應該在另一個程序請求空閒記憶體時釋放它的記憶體記憶體,但從我們所看到的情況來看,它沒有。
OOM 開始殺死其他重要程序,例如 postgres、redis 等。(可以看出,為了克服這個問題,我們將 RAM 增加到 183GB,現在可以使用但非常昂貴。mongo 使用 ~87GB 的 ram,幾乎是整個數據集大小的 4 倍)
所以,
- 這麼多記憶體使用量真的是預期的和正常的嗎?(根據文件,WiredTiger 最多使用約 60% 的 RAM 作為其記憶體,但考慮到數據集的大小,它甚至有足夠的數據來佔用 86GB 的 RAM 嗎?)
- 即使記憶體使用量是預期的,如果另一個程序開始請求更多記憶體,為什麼 mongo 不會釋放其分配的記憶體?在我們增加 RAM 之前,Linux oom 會不斷殺死其他各種正在執行的程序,包括 mongodb 本身,這會使系統完全不穩定。
謝謝 !
好的,所以在遵循 loicmathieu 和 jstell 提供的線索,並對其進行了一點探勘之後,我發現了關於使用 WiredTiger 儲存引擎的 MongoDB 的一些事情。如果有人遇到相同的問題,我會把它放在這裡。
我提到的記憶體使用執行緒都屬於 2012-2014 年,都早於 WiredTiger,並且正在描述原始 MMAPV1 儲存引擎的行為,該引擎沒有單獨的記憶體或不支持壓縮。
WiredTiger記憶體設置只控制 WiredTiger 儲存引擎直接使用的記憶體大小(不是 mongod 使用的總記憶體)。在 MongoDB/WiredTiger 配置中,許多其他東西可能會佔用記憶體,例如:
- WiredTiger 壓縮磁碟儲存,但記憶體中的數據未壓縮。
- 預設情況下,WiredTiger 不會在每次送出時同步數據,因此日誌文件也在 RAM 中,這會佔用記憶體。還提到為了有效地使用 I/O,WiredTiger 將 I/O 請求(記憶體未命中)分塊在一起,這似乎也佔用了一些 RAM(事實上,臟頁(已更改/更新的頁面)有一個更新列表將它們儲存在 Concurrent SkipList中)。
- WiredTiger 在其記憶體中保留多個版本的記錄(多版本並發控制,讀取操作在操作之前訪問最後送出的版本)。
- WiredTiger 將數據的校驗和保存在記憶體中。
- MongoDB 本身會消耗記憶體來處理打開的連接、聚合、伺服器端程式碼等。
考慮到這些事實,依賴在
show dbs;
技術上並不正確,因為它只顯示了數據集的壓縮大小。可以使用以下命令來獲取完整的數據集大小。
db.getSiblingDB('data_server').stats() # OR db.stats()
結果如下:
{ "db" : "data_server", "collections" : 11, "objects" : 266565289, "avgObjSize" : 224.8413545621088, "dataSize" : 59934900658, # 60GBs "storageSize" : 22959984640, "numExtents" : 0, "indexes" : 41, "indexSize" : 7757348864, # 7.7GBs "ok" : 1 }
因此,實際數據集大小 + 其索引似乎佔用了大約 68GB 的記憶體。
考慮到所有這些,我猜現在記憶體使用量是可以預期的,很好的部分是限制 WiredTiger 記憶體大小是完全可以的,因為它非常有效地處理 I/O 操作(如上所述)。
還有OOM的問題,為了克服這個問題,由於我們沒有足夠的資源來取出mongodb,所以我們降低了oom_score_adj,以防止OOM暫時殺死重要程序(意思是我們告訴OOM不要殺死我們的所需的過程)。