可能是你能找到的最完整最详细的中文版的Raft算法说明博客
内容来源都是原生的论文,可以保证内容的可靠性,并且对论文里面的很多细节做了扩展说明
心得体会
- raft系统中有超时的概念,每个节点有1个计时器,叫做election timer,超时会触发election timeout。在不同的业务场景下拥有2种功能:心跳监测计时和选举开始计时,
- 心跳监测计时:当role为follower时,收到一次leader的RPC、或者candidate的Vote RPC就清空一次心跳超时的计时器
- 选举开始计时:当role为candidate时,发起一次Vote就开始选举计时,只有到了超时时间自己还未选举出新leader,就自增任期和清空选举开始时间,再次发起Vote RPC
- 心跳超时的时间是固定的,而选举超时的时间是在一定区间内是随机的(150ms到300ms之间),这样设计是降低多个node同时voting的概率。
Raft集群中有3个操作:日志的复制(leader把新的日志发给所有的follower来追加新的command),日志的commit(超过半数复制都成功后,leader发起的追加确认成功),日志的apply(每个server把最新的值更新到自己的状态机里面),这是3个不同的概念。
Raft集群中有两个幂等性重试的概念:
leader给follower发RPC的时候,如果follower超时未响应,则leader会重试,直到得到Follower的回复,而且是幂等性的,避免重复操作。
还有一种重试的概念,就是follower节点崩溃后重新加入到集群中,数据差很多log,那么response也是false,那么leader也会重试,会更新 nextIndex、matchIndex和传对应的log,直到数据一致为止。
客户端在向服务端发起请求的时候,服务器可能因为异常而导致未能及时回复操作结果,客户端会定时发起重试,而且重试的requestID保持不变
选举过程中,新leader的数据不一定是最新最全的。比如在一个5节点的集群中,老leader有1条日志,只复制成功了1个节点,然后挂了,剩下的3个节点都没有这条日志,但是仍然可能选举成功,因为超过半数了。
所以说只有半数复制过了的消息,才能确保命令是执行成功了的,因为新leader肯定在这半数以内,但是如果未复制超过半数,那么该命令可能会丢失,依赖客户端的重试才能保证request不会丢失Raft集群中,所有的节点都有一定的独立性
- 每个节点都保存了一份相对完整的log[]和状态机
- 每个节点都有可能会在下个term成为leader
- 每个节点都直接管理各自快照的生成
Raft集群中没有锁的概念,所以正在写而又没有apply到状态机中的数据是读不到的,所以读取到的数据可能不是最最最新的数据
Raft集群成员数量的增加,可以提升系统的容错性,但是会降低系统的读写性能,每次写都需要半数节点复制成功,非常影响写的速度。读取的话,采用stale模式可以提升速度,否则,每次leader都要confirm半数节点自己的leaderdiwei