天天看點

MongoDB複制集與Raft協定異同點分析

此文已由作者溫正湖授權網易雲社群釋出。

歡迎通路網易雲社群,了解更多網易技術産品營運經驗。

一、日志複制流程:

a、raft leader節點在接收client請求後,先将請求寫到日志中,再将日志通過AppendEntries RPC發送到follow上。如果收到了大多數follow的确認消息,則對應日志可以在leader節點回放,之後follow上對應的日志也會被應用;

b、mongodb primary節點在接收到client/driver請求後,将資料變化寫到資料庫上,同時寫一份日志到oplog.rs集合中,secondary節點通過tail cursor将日志從primary(或sync source,即複制源)拉取到本地馬上進行回放(不會像mysql relay一樣緩存到磁盤上),回放完成前将對應的oplog日志儲存到本節點的oplog.rs集合。

//顯然有幾點不一樣:

1、raft是主動推日志,mongodb是secondary拉日志; 相對來說,拉取的方式可以減輕主節點的負擔。這點mongodb好些。

2、raft先寫日志,日志發送到大多數節點後再應用到狀态機。mongodb是先寫資料,然後寫日志,再通過日志拉取的方式應用到從節點。 如果日志比資料小,那麼raft更具有性能優勢,否則,相差無幾。

二、什麼時候傳回用戶端:

a、raft中, 是大多數節點已收到,還是寫入leader日志時? 通過“● Once new entry committed:  Leader executes command in its state machine, returns result to client”這句話可以知道,raft是等大多數節點收到日志,leader将日志應用到本節點後才傳回用戶端;

b、mongodb中,什麼時候傳回用戶端可以由使用者進行動态設定,設定項為writeConcern,通過rs.conf()可以擷取目前預設的writeConcern,預設置為w=1,即寫了primary後即傳回。也可以在每次寫操作時設定writeConcern,主要包括寫入到幾個節點,寫入逾時是多少,是否需要寫日志等。

// 是以,在這點上mongodb更加靈活,但早期設定的writeConcern級别太松,導緻丢資料嚴重。目前設定為寫了primary節點再傳回用戶端。

三、從節點什麼時候應用日志:

a、raft中,AppendEntries RPC攜帶了目前已經committed的log的資訊,這樣從節點就可以根據該資訊來将這之前的log應用到本節點;

b、mongod中,從節點從複制源擷取oplog資訊後,馬上在本節點并行回放;

//這點,mongod會更加簡潔。

四、誰能成為主節點:

a、raft,“Only servers with up-to-date logs can become leader”隻有擁有最新資料的節點才能成為主。// 4.21更新,raft也是跟MongoDB複制集一樣,資料比大多數節點性就可以。官方ppt中的這句話,up-to-date翻譯成最新容易引起誤解。

b、資料比大多數節點新就可以成為主節點,新主節點在提供對外服務前,會有catchupTimeoutMills時間的catchup過程,用來短暫複制其他節點更新的資料;

//資料是否比大多數節點新,判斷依據是根據日志來的

五、如何確定每個節點在一個term中隻投票一次:

a、raft “Each server gives only one vote per term (persist on disk)”,也就是說會将相應資訊持久化到磁盤上,具體可參考mongodb。

b、mongodb将投票資訊持久化到local庫下replset.election中,内容如:{ "_id" : ObjectId("58cbe1844857daa6e06ed9da"), "term" : NumberLong(4), "candidateIndex" : NumberLong(0) },記錄了在那個term中給誰(candidateIndex)投票了。通過_id字段的ObjectId對象能擷取投票時間。

六、新主是否會做catchup:

a、raft,“Leader’s log is “the truth””,主節點的資料是真理,新主産生後,不會從存活的從節點上拷最新的資料;

b、mongodb,預設會有2s的catchup時間,如果發現從節點資料比新主新,那麼在這時間内會catchup

//兩則不同的原因是,mongodb是個AP系統,C無法滿足。存在2種情況,如果設定為w=1,那麼如果主挂了,資料可能丢失。如果w=majority,那麼如果還未滿足majority時,主挂了,也就是說用戶端傳回錯誤,但這并不表示資料就寫入失敗了,需要等新主産生後進一步确認,因為即使新主本來沒有這部分資料,也可能在catchup節點從其他節點擷取。是以,這跟mysql等關系型資料庫不一樣。

七、主怎麼知道從已經收到日志/回放了:

a、raft,通過AppendEntries RPC傳回結果;

b、通過replSetUpdatePosition指令;

2017-03-30T10:48:12.839+0800 I COMMAND [conn647] command admin.$cmd command: replSetUpdatePosition { replSetUpdatePosition: 1, optimes: [ { durableOpTime: { ts: Timestamp 1490797135000|2, t: 3 }, appliedOpTime: { ts: Timestamp 1490797135000|2, t: 3 }, memberId: 0, cfgver: 454570 }, { durableOpTime: { ts: Timestamp 1490842087000|1, t: 4 }, appliedOpTime: { ts: Timestamp 1490842087000|1, t: 4 }, memberId: 1, cfgver: 454570 }, { durableOpTime: { ts: Timestamp 1490842087000|1, t: 4 }, appliedOpTime: { ts: Timestamp 1490842087000|1, t: 4 }, memberId: 2, cfgver: 454570 } ], $replData: { term: 4, lastOpCommitted: { ts: Timestamp 1490842087000|1, t: 4 }, lastOpVisible: { ts: Timestamp 0|0, t: -1 }, configVersion: 454570, replicaSetId: ObjectId('58cbe1844857daa6e06ed9d7'), primaryIndex: 0, syncSourceIndex: 0 } } numYields:0 reslen:22 locks:{} protocol:op_command 0ms      

replSetUpdatePosition不是周期性的,而是實時的。從節點每完成一次oplog回放,就向其複制源發送一個replSetUpdatePosition指令。

八、節點間是否有優先級:

a、raft,大家都是平等的。

b、mongodb,有優先級概念,priority可以是非負數。浮點型

九、是否支援鍊式複制:

a、raft,不支援;

b、mongodb支援鍊式複制。好處是減小了主上的壓力。尤其是在有很多從節點的場景下。不足之處是,這容易導緻某些從節點的複制延遲過大。

網易雲免費體驗館,0成本體驗20+款雲産品! 

更多網易技術、産品、營運經驗分享請點選。

相關文章:

【推薦】 BRVAH(讓RecyclerView變得更高效) (3)

【推薦】 從DevOps到Cloud Native,應用上雲姿勢全解鎖

【推薦】 聊一聊資料分析師這個職業