線上真實案例:mongo被OOM的一次歷險
前言
近期線上平臺出現(xiàn)一次故障,mongo數(shù)據(jù)庫被oom了,由于是高可用架構(gòu),重新選舉了主節(jié)點后,繼續(xù)工作,沒想到剛選舉完又被oom,mongo重啟達(dá)到了分鐘級別,多個節(jié)點被oom后,不能很快的拉起來提供服務(wù),對業(yè)務(wù)產(chǎn)生了巨大的影響。
分析
?目前從表面來看,有這樣幾個問題
1.內(nèi)存128g,在這么高的配置下都發(fā)生了OOM,那么看來是有優(yōu)化空間的,mongo為什么吃了這么多內(nèi)存 2.為什么啟動這么慢
通過表分析,發(fā)現(xiàn)有很多大表,其中一個巨大的表占用了110個g,且有頻繁的讀寫。原因是因為有很多冷數(shù)據(jù),未做冷熱數(shù)據(jù)分離。
優(yōu)化1
刪除一些歷史遺留數(shù)據(jù)
Mongo優(yōu)化
從mongoDB 3.2開始支持多種存儲引擎,其中默認(rèn)為 Wired Tiger。我們使用的正是mongodb 3.2版本
MongoDB 不是內(nèi)存數(shù)據(jù)庫,但是為了提供高效的讀寫操作存儲引擎會最大化的利用內(nèi)存緩存。
MongoDB 的讀寫性能都會隨著數(shù)據(jù)量增加達(dá)到瓶頸,這其中的根本原因就是內(nèi)存是否能滿足全部的數(shù)據(jù)。
答案肯定是否定的。
業(yè)務(wù)的發(fā)展超過了機(jī)器的配置,那么出現(xiàn)問題只是時間問題,無論在怎么堆機(jī)器的配置,數(shù)據(jù)量的增長就是慢性毒藥,只能祈禱毒發(fā)身亡那一天晚一點到來。
那么mongo怎么來解決這個問題的呢?
Evict
內(nèi)存淘汰時機(jī)由eviction_target(內(nèi)存使用量)和eviction_dirty_target(內(nèi)存臟數(shù)據(jù)量)來控制,而內(nèi)核默認(rèn)是有Evict線程去處理的。
定義表格
那他的默認(rèn)策略到底是多少呢?
網(wǎng)上說什么各種比例的都有,所以我clone對應(yīng)版本的源代碼,來找答案 ,以下分析基于3.2.13
版本
?.全局搜索下關(guān)鍵字和eviction_dirty_target

參數(shù)名稱含義百分比eviction_target當(dāng)Cache的使用量達(dá)到了對應(yīng)的百分比時觸發(fā)Evict線程淘汰page80%eviction_trigger當(dāng)Cache的使用量達(dá)到了對應(yīng)的百分比時觸發(fā)Evict線程和用戶線程淘汰page95%eviction_dirty_target當(dāng)”臟數(shù)據(jù)“所占Cache達(dá)到對應(yīng)的百分比觸發(fā)Evict線程淘汰page5%eviction_dirty_trigger當(dāng)”臟數(shù)據(jù)“所占Cache達(dá)到對應(yīng)的百分比觸發(fā)Evict線程和用戶線程淘汰page20%
一般我們會在啟動mongo的時候,我們可以通過日志來觀察調(diào)用wiredtiger_open的參數(shù)

細(xì)心的同學(xué)會發(fā)現(xiàn),日志上打印的參數(shù)和我們截圖的參數(shù)并不符合。比如日志中?eviction=(threads_min=4,threads_max=4)
而我們看源代碼內(nèi)容是eviction=(threads_max=8," "threads_min=1)
?注:這里的thread線程是上面提到的Evict 線程
帶著疑問:我們深入源代碼分析下
?
首先進(jìn)入main函數(shù)mongoDbMain

?
main函數(shù)末尾會初始化并且監(jiān)聽端口

?
初始化和監(jiān)聽端口里會去檢查數(shù)據(jù)庫和版本

?
初始化WiredTigerFactory

?
初始化WiredTigerKVEngine

?
在WiredTigerKVEngine我們能找到答案,這里傳入的參數(shù)覆蓋了上面的配置

這上面的ss,則是啟動mongo打印輸出的日志。
通過上面的代碼,我們可以看到一個關(guān)鍵指標(biāo)close_idle_time=100000
(~28h),這個時間被硬編碼在代碼里。
close_idle_time
意義如下。在嘗試關(guān)閉文件句柄之前,文件句柄需要空閑的時間(以秒為單位)。設(shè)置為 0 表示不關(guān)閉空閑句柄
在Evict線程進(jìn)行工作的時候,文件句柄在28小時內(nèi),一直處于空閑狀態(tài)才會被關(guān)閉。
好處是:增加了命中率,壞處是Evict不及時
對于我們目前的業(yè)務(wù)來說,這個值太長了,所以我們需要調(diào)整它。
如何調(diào)整
以下調(diào)整建議在業(yè)務(wù)低峰期進(jìn)行
?運行中更改
我們在不重啟mongo下進(jìn)行更改,缺點是重啟后失效。
?
基于文件修改
wiredTiger各種參數(shù)的解釋[1]
Storage Engine API[2]
mongoDB高級選項[3]
總結(jié)
問題其實還是在于,冷熱數(shù)據(jù)不分,很多遺留數(shù)據(jù),導(dǎo)致系統(tǒng)的不穩(wěn)定性,出現(xiàn)各種問題。數(shù)據(jù)量到一定體系的時候,可以使用數(shù)據(jù)倉庫了。
References
[1]
?wiredTiger各種參數(shù)的解釋:?http://source.wiredtiger.com/2.8.0/group__wt.html#ga9e6adae3fc6964ef837a62795c7840ed[2]
?Storage Engine API:?https://mongodbsource.github.io/master/globals.html[3]
?mongoDB高級選項:?https://www.mongodb.com/docs/ops-manager/current/reference/deployment-advanced-options/#storage