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支持鏈式複製。好處是減小了主上的壓力。尤其是在有很多從節點的場景下。不足之處是,這容易導致某些從節點的複製延遲過大。

持續總結中。。
推薦閱讀:

用 perf 和 SystemTap 跟蹤 MongoDB 訪問超時
用 Python 和 MongoDB 構建千萬級用戶的後台靠譜嗎?
MongoDB 基礎教程--單機安裝與配置
MongoDB的一些基本操作

TAG:分布式系统 | MongoDB | 数据库 |