这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记
服务器通过共识算法,对某条操作是否添加进日志达成共识,各节点都顺序执行这份日志就能保持在一个一致的状态。
基础
节点类型
- Leader:发起心跳,创建日志,同步日志
- Candidate:Leader选举算法时的临时角色
- Follower:接收来自Leader的心跳、日志同步
Follower == backup?
任期
term是一个raft时间段,term开始时进行election,数个Candidate尝试竞争Leader。一个term内一定要有一个Leader。term同时类似版本号,Candidate或Leader发现自己的term过期时立刻退回Follower。过期的term会更新到收到值。过期的term消息会被抛弃。
日志
- entry:每一个事件成为entry。只有leader可以创建,格式为
<term,index,cmd> - log:由entry构成的数组。index是在自己log中的序列。entry总是先被添加到leader自己的日志中,然后发起共识请求,达成共识的提交。Follower只能从Leader获取新日志和当前的commited index,然后应用到自己的log
选举
raft使用心跳机制来触发Leader选举
Leader的心跳包会刷新Follower的选举超时时间
只要有一个Follower超时时间到就会发起选举
Candidate获得多数选票成为Leader:
这个N怎么算,N个candidate?怎么知道有N个?还是说N个总结点?如果掉了很多节点但没过半是不是选举有概率进行非常多次?
Raft使用随机化选举超时时间来避免激烈的选举竞争。节点每次选举过后,设置一个随机的超时时间,各个节点的超时时间不同,使得大多数情况下只有一个服务器会率先超时然后完成选举。
日志复制(传播更新)
Leader生成entry写入自己的log,然后广播该entry
Follower收到entry加入自己的log,并返回同意。那我不同意呢?
leader收到了多数同意,就记这个entry是commited
对于entry,raft保证如下性质:
-
在两个日志中,如果两个entry拥有一样的term和index,那么有相同的cmd
- 因为只有leader可以产生entry
-
再两个日志中,如果两个entry拥有一样的term和index,那么前面的entry一定相同
- 一致性检查
一致性检查如下:Leader给每个follower维护nextIndex,表示下一条给他的entry索引。新Leader开始时,会将所有nextIndex设置为自己的index+1。如果一个Follower收到的nextIndex和自己的index不一致会返回失败,随后Leader逐步递减nextIndex并重试,最终到达一个一致的地方,并移除所有不一致的部分,修改为Leader所给的entries。至此Follower和Leader的日志达成一致。
安全性
选举限制
Candidate会拒绝entry比自己旧的投票请求。先比较term,在比较index
节点崩溃
Leader崩溃时,超时选举,选举期间服务不可用
Follower或Candidate崩溃只需要通过AppendEntriesRPC同步
响应时间/选举超时时间/机器平均健康时间
broadcastTime << electionTimeout: 使得Leader能通过心跳来避免频繁发生选举electionTimeout << MTBF: 使得系统稳定运行,选举不可用时间只占全部时间的很小一部分