Zookeeper & Etcd 关键对比汇总
1. 选举
1.1 Etcd选举过程
每个节点启动时作为
Follwer角色,经过一个ElectionTimeout(启动时随时生成的默认150ms~300ms)后进入Candidate状态,并向其他节点发送消息MsgVote消息(本节点的Term、最新的日志Index,最新日志的LogTerm);其他节点收到投标后,进行两步判断:
- 预判断,:
r.Vote==m.Form(是否已经投标给该节点)- 当前节点未投标且无leader节点;
- 对于预投标(
PreVote),消息的任期比当前节点大;
- 任何一个条件判断则可以进入正式判断:
- 若消息中
日志Term对当前节点大则投给消息发送方,若日志Term相等,Index比当前节点大则也将票投给消息发送方r.raftLog.isUpToDate(m.Index, m.LogTerm)
- 若消息中
- 若上面的判断失败,则返回拒绝
- 预判断,:
当发起投标方收到半数以上的头条,则转换自己的角色
becomeLader(raft.go/stepCandidate),并广播一条空消息给其他所有节点。- Candidate –> Leader
- Candidate –> Follower
广播时间 << 选举超时时间 << 平均故障间隔时间
1.2 Zookeeper选举过程
双向心跳,Leader收不到半数以上的Follower节点发来的心跳则发起选举;Follower未收到Leader心跳则发起选举,选举时状态切换成LOOKING。
投票节点:首先将节点状态转变成
LOOKING状态;投票节点:将自己作为
(SID、ZXID)广播给其他节点;其他节点:接收其他节点的选举投票;
其他节点:如果接收的选举纪元大于本地的选举轮数则更新本地选举轮数,并将接收的投票跟本地投票比较后更新本地投票,再广播出去。否则执行4;
其他节点:判断外部投票是否优于本地,如果是则更新本地提议再广播出去;
比较纪元大小(最新日志记录的纪元,并不是当前选举纪元);
纪元相等的情况,比较
Zxid;Zxid相等的情况下 则比较Sid;return ((newEpoch > curEpoch) ||
((newEpoch == curEpoch) && ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));
投票节点:收集投票提议,并进行统计,若有节点收集的投票大于一半以上则认为该节点为
Leader节点;投票节点: 若投票选定节点是该节点则转变自己的服务器状态为
LEADING,若不是则转换成FOLLOWING | OBSERVING。
- LOOKING –> LEADING
- LOOKING –> FOLLOWING
2. 数据同步
2.1 Zookeeper数据同步
数据同步分为四种DIFF、TRUNC、TRUNC+DIFF、SNAP
设 Learner节点最后处理的ZXID为peerLastZxid,Leader服务器提议缓存队列commitedLog最小最大ZXID为minCommitedLog、maxCommitedLog;
- 若
peerLastZxid小于minCommitedLog,则执行SNAP; - 若
peerLastZxid在minCommitedLog与maxCommitedLog之间,则执行DIFF; - 若
peerLastZxid大于maxCommitedLog时,则执行TRUNC; - 若
peerLastZxid在minCommitedLog与maxCommitedLog之间但又不在leader中,则TRUNC+DIFF。
2.2 Etcd数据同步
Etcd 中Leader为每个从节点保存两个信息nextIndex(下一次要复制的位置)、matchIndex(已经匹配的位置)
当从
Candidate角色转换成Leader角色后,会将所有节点的nextIndex改为当前节点最大的Index,matchIndex设置为 0,向所有节点发送Append Entries信息;若接收到信息的节点的
commitedId大于发送过来的nextIndex,则告诉Leader该索引号;若
msg.Index&Term在节点日志中,则告知Leader节点目前的mLastIndex;若不匹配,则发送拒绝,并返回其日志中的
LastIndex。若节点信息对不上
nextIndex则返回日志失败,Leader不断前移nextIndex进行循环往复尝试,直至节点追加成功;
3. Watch机制
3.1 Zookeeper
Zookeeper的watch由引用层的WatchManager进行管理,其中包含NodeWatcher和ChildWatcher:
- 当有数据更新时同时会调用
WatchManager进行触发事件; - 从
WatcherManager中筛选出符合条件的Watcher触发下发,并把映射给摘除。- 只会触发一次,且不会把真正的数据下发下去而只下发
通知状态、事件类型、节点路径,具体变更数据由Client自行来查询; Watcher事件传递到Client触发后也会删除映射关系。
- 只会触发一次,且不会把真正的数据下发下去而只下发
因此存在丢失的可能:
- 在对于同一个key或者同一范围的监听,若修改速度迅速,会漏事件。
3.2 Etcd
Etcd由两个协程和两个WatcherGroup来管理Watcher事件。详细见:Etcd Watch机制
- 带版本号监听;
- 连续监听不是单次监听。
4. 线性一致性
zab&Raft 只是共识算法,并非线性一致性,实现线性一致性需要上层做出努力。如etcd的线性一致性读。
什么是线性一致性读?
对于同一对象,读写请求按顺序线性进行。(读到最新写的数据)