MongoDB複製集全量同步改進

MongoDB副本集數據同步方式數據庫

intial sync,能夠理解爲全量同步。併發

replication,追同步源的oplog,能夠理解爲增量同步。性能

下面會詳細介紹MongoDB數據同步的實現原理。線程

initial sync設計

Secondary節點當出現以下情況時,須要先進行全量同步。server

oplog爲空。blog

local.replset.minvalid集合裏_initialSyncFlag字段設置爲true。索引

內存標記initialSyncRequested設置爲true。隊列

這3個場景分別對應內存

新節點加入,無任何oplog,此時需先進性initial sync。

initial sync開始時,會主動將_initialSyncFlag字段設置爲true,正常結束後再設置爲false;若是節點重啓時,發現_initialSyncFlag爲true,說明上次全量同步中途失敗了,此時應該從新進行initial sync。

當用戶發送resync命令時,initialSyncRequested會設置爲true,此時會從新開始一次initial sync。

intial sync流程

全量同步開始,設置minvalid集合的_initialSyncFlag。
獲取同步源上最新oplog時間戳爲t1。
全量同步集合數據 (耗時)。
獲取同步源上最新oplog時間戳爲t2。
重放[t1, t2]範圍內的全部oplog。
獲取同步源上最新oplog時間戳爲t3。
重放[t2, t3]範圍內全部的oplog。
創建集合全部索引 (耗時)。
獲取同步源上最新oplog時間戳爲t4。
重放[t3, t4]範圍內全部的oplog。
全量同步結束,清除minvalid集合的_initialSyncFlag。

Replication

initial sync結束後,接下來Secondary就會『不斷拉取主上新產生的oplog並重放』,這個過程在Secondary同步慢問題分析也介紹過,這裏從另外一個角度再分析下。

MongoDB複製集全量同步改進MongoDB複製集全量同步改進

producer thread,這個線程不斷的從同步源上拉取oplog,並加入到一個BlockQueue的隊列裏保存着。

replBatcher thread,這個線程負責逐個從producer thread的隊列裏取出oplog,並放到本身維護的隊列裏。

sync線程將replBatcher thread的隊列分發到默認16個replWriter線程,由replWriter thread來最終重放每條oplog。

問題來了,爲何一個簡單的『拉取oplog並重放』的動做要搞得這麼複雜?

性能考慮,拉取oplog是單線程進行,若是把重放也放到拉取的線程裏,同步勢必會很慢;因此設計上producer thread只幹一件事。

爲何不將拉取的oplog直接分發給replWriter thread,而要多一個replBatcher線程來中轉?

oplog重放時,要保持順序性,並且遇到createCollection、dropCollection等DDL命令時,這些命令與其餘的增刪改查命令是不能並行執行的,而這些控制就是由replBatcher來完成的。

注意事項

initial sync單線程複製數據,效率比較低,生產環境應該儘可能避免initial sync出現,需合理配置oplog,按默認『5%的可用磁盤空間』來配置oplog在絕大部分場景下都能知足需求,特殊的case(case1, case2)可根據實際狀況設置更大的oplog。

新加入節點時,能夠經過物理複製的方式來避免initial sync,將Primary上的dbpath拷貝到新的節點,直接啓動,這樣效率更高。

當Secondary上須要的oplog在同步源上已經滾掉時,Secondary的同步將沒法正常進行,會進入RECOVERING的狀態,需向Secondary主動發送resyc命令從新同步。3.2版本目前有個bug,可能致使resync不能正常工做,必須強制(kill -9)重啓節點,詳情參考SERVER-24773。

生產環境,最好經過db.printSlaveReplicationInfo()來監控主備同步滯後的狀況,當Secondary落後太多時,要及時調查清楚緣由。

當Secondary同步滯後是由於主上併發寫入過高致使,(db.serverStatus().metrics.repl.buffer.sizeBytes持續接近db.serverStatus().metrics.repl.buffer.maxSizeBytes),可經過調整Secondary上replWriter併發線程數來提高。

MongoDB 3.4複製集全量同步改進

MongoDB 3.2版本複製集同步的過程參考上面,在MongoDB 3.4版本里MongoDB對複製集同步的全量同步階段作了2個改進:

在拷貝數據的時候同時創建全部的索引,在以前的版本里,拷貝數據時會先創建_id索引,其他的索引在數據拷貝完以後集中創建。

在拷貝數據的同時,會把同步源上新產生的oplog拉取到本地local數據庫的臨時集合存儲着,等數據全量拷貝完,直接讀取本地臨時集合的oplog來應用,提高了追增量的效率,同時也避免了同步源上oplog不足致使沒法同步的問題。

MongoDB複製集全量同步改進MongoDB複製集全量同步改進

上圖描述了這2個改進的效果,實測了『10GB的數據,包含64個集合,每一個集合包含2個索引字段,文檔平均1KB,3.4版本的全量同步性能約有20%的提高,若是數據集很大,而且在同步的過程當中有寫入,提高的效果會更明顯,而且完全解決了因同步源oplog不足而致使進入RECOVERING狀態沒法同步的問題。

相關文章
相關標籤/搜索