線上真實案例:mongo被OOM的一次歷險【似乎靠譜】

前言

近期線上平臺出現一次故障,mongo數據庫被oom了,由於是高可用架構,重新選舉了主節點後,繼續工作,沒想到剛選舉完又被oom,mongo重啓達到了分鐘級別,多個節點被oom後,不能很快的拉起來提供服務,對業務產生了巨大的影響。

分析

•目前從表面來看,有這樣幾個問題

1.內存128g,在這麼高的配置下都發生了OOM,那麼看來是有優化空間的,mongo爲什麼吃了這麼多內存 2.爲什麼啓動這麼慢

通過表分析,發現有很多大表,其中一個巨大的表佔用了110個g,且有頻繁的讀寫。原因是因爲有很多冷數據,未做冷熱數據分離。

優化1

刪除一些歷史遺留數據

Mongo優化

從mongoDB 3.2開始支持多種存儲引擎,其中默認爲 Wired Tiger。我們使用的正是mongodb 3.2版本

MongoDB 不是內存數據庫,但是爲了提供高效的讀寫操作存儲引擎會最大化的利用內存緩存。

MongoDB 的讀寫性能都會隨着數據量增加達到瓶頸,這其中的根本原因就是內存是否能滿足全部的數據。

答案肯定是否定的。

業務的發展超過了機器的配置,那麼出現問題只是時間問題,無論在怎麼堆機器的配置,數據量的增長就是慢性毒藥,只能祈禱毒發身亡那一天晚一點到來。

那麼mongo怎麼來解決這個問題的呢?

Evict

內存淘汰時機由eviction_target(內存使用量)和eviction_dirty_target(內存髒數據量)來控制,而內核默認是有Evict線程去處理的。

定義表格

那他的默認策略到底是多少呢?

網上說什麼各種比例的都有,所以我clone對應版本的源代碼,來找答案 ,以下分析基於3.2.13版本

•.全局搜索下關鍵字和eviction_dirty_target圖片

參數名稱 含義 百分比
eviction_target 當Cache的使用量達到了對應的百分比時觸發Evict線程淘汰page 80%
eviction_trigger 當Cache的使用量達到了對應的百分比時觸發Evict線程和用戶線程淘汰page 95%
eviction_dirty_target 當”髒數據“所佔Cache達到對應的百分比觸發Evict線程淘汰page 5%
eviction_dirty_trigger 當”髒數據“所佔Cache達到對應的百分比觸發Evict線程和用戶線程淘汰page 20%

一般我們會在啓動mongo的時候,我們可以通過日誌來觀察調用wiredtiger_open的參數圖片

細心的同學會發現,日誌上打印的參數和我們截圖的參數並不符合。比如日誌中 eviction=(threads_min=4,threads_max=4)而我們看源代碼內容是eviction=(threads_max=8," "threads_min=1) 注:這裏的thread線程是上面提到的Evict 線程

帶着疑問:我們深入源代碼分析下

首先進入main函數mongoDbMain圖片

main函數末尾會初始化並且監聽端口圖片

初始化和監聽端口裏會去檢查數據庫和版本圖片

初始化WiredTigerFactory圖片

初始化WiredTigerKVEngine圖片

在WiredTigerKVEngine我們能找到答案,這裏傳入的參數覆蓋了上面的配置圖片

這上面的ss,則是啓動mongo打印輸出的日誌。

通過上面的代碼,我們可以看到一個關鍵指標close_idle_time=100000(~28h),這個時間被硬編碼在代碼裏。

close_idle_time意義如下。在嘗試關閉文件句柄之前,文件句柄需要空閒的時間(以秒爲單位)。設置爲 0 表示不關閉空閒句柄

在Evict線程進行工作的時候,文件句柄在28小時內,一直處於空閒狀態纔會被關閉。

好處是:增加了命中率,壞處是Evict不及時

對於我們目前的業務來說,這個值太長了,所以我們需要調整它。

如何調整

以下調整建議在業務低峯期進行

•運行中更改

我們在不重啓mongo下進行更改,缺點是重啓後失效。

db.adminCommand({setParameter: 1, wiredTigerEngineRuntimeConfig: "eviction=(threads_min=1,threads_max=8)"})

複製代碼

基於文件修改

systemLog:
destination: file
path: "/var/log/mongodb/mongod.log"
storage:
 dbPath: "/opt"
 wiredTiger:
     engineConfig:
         configString: "eviction_dirty_target=60,async=(enabled=true,ops_max=1024,threads=2)"
processManagement:
fork: true
net:
bindIp: 127.0.0.1
port: 27018

複製代碼

wiredTiger各種參數的解釋[1]

Storage Engine API[2]

mongoDB高級選項[3]

總結

問題其實還是在於,冷熱數據不分,很多遺留數據,導致系統的不穩定性,出現各種問題。數據量到一定體系的時候,可以使用數據倉庫了。

References

[1] wiredTiger各種參數的解釋: source.wiredtiger.com/2.8.0/group…
[2] Storage Engine API: mongodbsource.github.io/master/glob…
[3] mongoDB高級選項: www.mongodb.com/docs/ops-ma…

本文使用 文章同步助手 同步

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章