MongoDB复制集与Raft协议异同点分析

勿忘初心2018-10-19 09:30

此文已由作者温正湖授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


一、日志复制流程:

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+款云产品! 

更多网易技术、产品、运营经验分享请点击




相关文章:
【推荐】 Kubernetes性能测试实践