天天看點

MongoDB原理:複制集狀态同步機制

mongodb複制集(3.0版本)之間通過心跳資訊來同步成員的狀态資訊,每個節點會周期性的向複制集内其它的成員發送心跳資訊來擷取狀态,如rs.status()看到的複制集狀态資訊。

一次心跳請求分3個階段 (主動發起心跳請求的節點稱為源,接受到心跳請求的成為目标)

源向目标發送心跳請求

目标處理心跳請求,并向源發送應答

源接受到心跳應答,更新目标節點狀态

接下來将介紹這3個階段裡的主要狀态同步邏輯

預設配置下,複制集的節點每隔2s會向其他成員發送一次心跳請求,即發送replsetheartbeat指令請求,心跳請求的内容類似如下(通過mongosniff抓包擷取),主要包含replsetname、發送心跳的節點位址、複制集版本等。

複制內建員收到心跳請求後,就開始處理請求,并将處理的結果回複給請求的節點。

如果自身不是複制集模式、或複制集名稱不比對,則傳回錯誤應答

如果源節點的複制集配置(rs.conf()的内容)版本比自己低,則将自身的配置加入到心跳應答消息裡

将節點自身的oplog及其他狀态資訊等加入到心跳應答消息

如果自身是未初始化狀态,則立即向源節點發送心跳請求,以更新複制集配置

階段3是最主要的處理部分,節點收到心跳應答後,會根據應答消息來更新對端節點的狀态,并根據最終的狀态确定是否需要進行重新選舉。

收到心跳應答時,如果是錯誤應答(心跳消息逾時未應答相當于收到了錯誤應答),則

如果目前重試次數 <= kmaxheartbeatretries(預設為2),并且上一次發送心跳在kdefaultheartbeattimeoutperiod(預設為10)時間内,則立即發送下一次心跳

當失敗次數超過kmaxheartbeatretries,或者上一次心跳時間到現在超過kdefaultheartbeattimeoutperiod,則認為節點down

如果對端的複制集版本比自己高,則更新自己的配置并持久化到local資料庫中

根據應答消息更新對端的狀态資訊

如果自身是主節點,當發現有優先級更高的節點可被選為主,則主動降級

如果目前沒有主節點,則主動發起新的選舉,當得到大多數節點同意後,即可選出新的主節點

總的來說,mongodb通過心跳來同步節點間資訊并觸發選舉,最終将複制集達到統一的狀态,但過程的正确性沒有理論依據,mongodb-3.2版本裡,使用了新版本的複制集通信協定,改用raft來選舉,能進一步降低故障發現恢複時間,目前還在學習中。