前言
近期線上平臺出現(xiàn)一次故障赔嚎,mongo數(shù)據(jù)庫被oom了润讥,由于是高可用架構(gòu)转锈,重新選舉了主節(jié)點后,繼續(xù)工作象对,沒想到剛選舉完又被oom黑忱,mongo重啟達到了分鐘級別,多個節(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開始支持多種存儲引擎检柬,其中默認為 Wired Tiger。我們使用的正是mongodb 3.2版本
MongoDB 不是內(nèi)存數(shù)據(jù)庫竖配,但是為了提供高效的讀寫操作存儲引擎會最大化的利用內(nèi)存緩存何址。
MongoDB 的讀寫性能都會隨著數(shù)據(jù)量增加達到瓶頸,這其中的根本原因就是內(nèi)存是否能滿足全部的數(shù)據(jù)进胯。
答案肯定是否定的用爪。
業(yè)務(wù)的發(fā)展超過了機器的配置,那么出現(xiàn)問題只是時間問題胁镐,無論在怎么堆機器的配置偎血,數(shù)據(jù)量的增長就是慢性毒藥,只能祈禱毒發(fā)身亡那一天晚一點到來希停。
那么mongo怎么來解決這個問題的呢烁巫?
Evict
內(nèi)存淘汰時機由eviction_target(內(nèi)存使用量)和eviction_dirty_target(內(nèi)存臟數(shù)據(jù)量)來控制,而內(nèi)核默認是有Evict線程去處理的宠能。
定義表格
那他的默認策略到底是多少呢?
網(wǎng)上說什么各種比例的都有磁餐,所以我clone對應(yīng)版本的源代碼违崇,來找答案 阿弃,以下分析基于3.2.13
版本
?.全局搜索下關(guān)鍵字和eviction_dirty_target
參數(shù)名稱 | 含義 | 百分比 |
eviction_target | 當Cache的使用量達到了對應(yīng)的百分比時觸發(fā)Evict線程淘汰page | 80% |
eviction_trigger | 當Cache的使用量達到了對應(yīng)的百分比時觸發(fā)Evict線程和用戶線程淘汰page | 95% |
eviction_dirty_target | 當”臟數(shù)據(jù)“所占Cache達到對應(yīng)的百分比觸發(fā)Evict線程淘汰page | 5% |
eviction_dirty_trigger | 當”臟數(shù)據(jù)“所占Cache達到對應(yīng)的百分比觸發(fā)Evict線程和用戶線程淘汰page | 20% |
一般我們會在啟動mongo的時候,我們可以通過日志來觀察調(diào)用wiredtiger_open的參數(shù)
細心的同學會發(fā)現(xiàn)羞延,日志上打印的參數(shù)和我們截圖的參數(shù)并不符合渣淳。比如日志中?eviction=(threads_min=4,threads_max=4)
而我們看源代碼內(nèi)容是eviction=(threads_max=8," "threads_min=1)
?注:這里的thread線程是上面提到的Evict 線程
帶著疑問:我們深入源代碼分析下
?
首先進入main函數(shù)mongoDbMain
?
main函數(shù)末尾會初始化并且監(jiān)聽端口
?
初始化和監(jiān)聽端口里會去檢查數(shù)據(jù)庫和版本
?
初始化WiredTigerFactory
初始化WiredTigerKVEngine
在WiredTigerKVEngine我們能找到答案,這里傳入的參數(shù)覆蓋了上面的配置
這上面的ss伴箩,則是啟動mongo打印輸出的日志入愧。
通過上面的代碼,我們可以看到一個關(guān)鍵指標close_idle_time=100000
(~28h)嗤谚,這個時間被硬編碼在代碼里棺蛛。
close_idle_time
意義如下。在嘗試關(guān)閉文件句柄之前巩步,文件句柄需要空閑的時間(以秒為單位)旁赊。設(shè)置為 0 表示不關(guān)閉空閑句柄
在Evict線程進行工作的時候,文件句柄在28小時內(nèi)椅野,一直處于空閑狀態(tài)才會被關(guān)閉终畅。
好處是:增加了命中率,壞處是Evict不及時
對于我們目前的業(yè)務(wù)來說竟闪,這個值太長了离福,所以我們需要調(diào)整它。
如何調(diào)整
以下調(diào)整建議在業(yè)務(wù)低峰期進行
?運行中更改
我們在不重啟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各種參數(shù)的解釋[1]
Storage Engine API[2]
mongoDB高級選項[3]
總結(jié)
問題其實還是在于,冷熱數(shù)據(jù)不分鲸湃,很多遺留數(shù)據(jù)赠涮,導致系統(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
本文使用 文章同步助手 同步