MongoDB Secondary同步慢問題分析

GiuseppeBro 8年前發布 | 16K 次閱讀 MongoDB NoSQL數據庫

問題背景

最近生產環境出現多次Primary寫入QPS太高,導致Seconary的同步無法跟上的問題(Secondary上的最新oplog時間戳比Primary上最舊oplog時間戳小),使得Secondary變成RECOVERING狀態,這時需要人工介入處理,向Secondary發送resync命令,讓Secondary重新全量同步一次。

同步過程

下圖是MongoDB數據同步的流程

Primary上的寫入會記錄oplog,存儲到一個固定大小的 capped collection 里,Secondary主動從Primary上拉取oplog并重放應用到自身,以保持數據與Primary節點上一致。

initial sync

新節點加入(或者主動向Secondary發送resync)時,Secondary會先進行一次initial sync,即全量同步,遍歷Primary上的所有DB的所有集合,將數據拷貝到自身節點,然后讀取『全量同步開始到結束時間段內』的oplog并重放。全量同步不是本文討論的重點,將不作過多的介紹。

tailing oplog

全量同步結束后,Secondary就開始從結束時間點建立tailable cursor,不斷的從同步源拉取oplog并重放應用到自身,這個過程并不是由一個線程來完成的,mongodb為了提升同步效率,將拉取oplog以及重放oplog分到了不同的線程來執行。

  • producer thread,這個線程不斷的從同步源上拉取oplog,并加入到一個BlockQueue的隊列里保存著,BlockQueue最大存儲240MB的oplog數據,當超過這個閾值時,就必須等到oplog被replBatcher消費掉才能繼續拉取。
  • replBatcher thread,這個線程負責逐個從producer thread的隊列里取出oplog,并放到自己維護的隊列里,這個隊列最多允許5000個元素,并且元素總大小不超過512MB,當隊列滿了時,就需要等待oplogApplication消費掉。
  • oplogApplication會取出replBatch thread當前隊列的所有元素,并將元素根據docId(如果存儲引擎不支持文檔鎖,則根據集合名稱)分散到不同的replWriter線程,replWriter線程將所有的oplog應用到自身;等待所有oplog都應用完畢,oplogApplication線程將所有的oplog順序寫入到local.oplog.rs集合。

producer的buffer和apply線程的統計信息都可以通過db.serverStatus().metrics.repl來查詢到,在測試過程中,向Primary模擬約10000 qps的寫入,觀察Secondary上的同步,寫入速率遠小于Primary,大致只有3000左右的qps,同時觀察到 producer的buffer很快就達到飽和,可以判斷出oplog重放的線程跟不上 。

默認情況下,Secondary采用16個replWriter線程來重放oplog,可通過啟動時設置replWriterThreadCount參數來定制線程數,當提升線程數到32時,同步的情況大大改觀,主備寫入的qps基本持平,主備上數據同步的延時控制在1s以內,進一步驗證了上述結論。

改進思路

如果因Primary上的寫入qps很高,經常出現Secondary同步無法追上的問題,可以考慮以下改進思路

參考資料

 

來自: http://blog.yunnotes.net/index.php/mongodb-scondary-cannot-catchup/

 

 本文由用戶 GiuseppeBro 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!