Raft 一致性算法

Redis内使用了Raft一致性算法做集群的选主和哨兵的选主,后来又了解了一下,作如下笔记。
笔记内主要回答了一些自己不会的点,Raft的详细说明,可从参考的两篇博文中得知更多。

一般操作

当客户端连接集群的任意节点的时候,任意节点会把客户端的连接导向到当前的leader上,所有操作在leader上完成。
当客户端发来请求的时候,leader先在自身记录日志,然后广播给各follower,各follower也记录日志,然后回复响应。当leader得到过半的follower的响应之后,leader会提交本次事务,返回给客户端响应,同时leader广播各节点提交事务。

选主算法

在每个节点上,都有timeout时间,随心跳检测不断重置。
因为网络的关系,各节点timeout流逝的并不相同,当leader没有响应之后,若干个follower,会有先有后的发现leader失联。
先达到timeout的follower会变为candidate,它会给其他节点发送“推荐自己称为下一个leader”的投票请求,每一个节点,只会接受第一个投票请求,并对其后的投票请求返回它接受的第一个投票请求的节点信息,帮助其他节点寻找到下一任leader。
每个节点只能接受第一个投票请求保证了,一个集群内,一轮投票,至多只有一个节点能获得多数节点的投票,才可能称为leader。当然,也有可能,没有任何一个节点获得多数节点的投票。这个时候,集群的配置纪元+1,各节点等待超时后,进行下一轮投票,直到选出leader。(为了避免出现持续的没有节点得到多数投票的事件,超时时间不是一个定值,而是随机一个区间内的值)

日志同步

leader正常运行的时候,日志同步自然是好的,各个节点的日志虽然不会立刻同步,但是leader上总有最完整的日志,一段时间之后,其他节点也总会同步到完成的日志。问题出现在leader down掉之后,新的leader如何保证有最完整的日志,即已经在旧leader上提交的事务,但是如果旧leader没来得及同步,这个时候旧leader down掉了,新的leader如何还能续上它们。

这个问题,需要进一步细化选主算法,之前的选主算法并没有考虑节点内日志的状态,现在需要考虑日志状态。
Raft进一步规定:
1. 选主的时候,candidate的投票请求需要带上自身的日志信息(纪元编号和最后纪元的日志index),如果其他节点的纪元编号和日志index大于candidate节点的,其他节点将拒绝投票。
2. 一个日志被提交,不仅要求当前日志被集群的多数回应为已记录,并且还要求,当前leader任期内的至少一个新日志也一同被集群大多数回应为已记录。此时,以前任期的日志才会和新任期的日志一同提交。这一条避免了,如果集群多数节点保存了低纪元的日志A,导致A已提交,而新成为leader的节点却没有低纪元日志A,却有一个高纪元的日志B,进而要求删除日志A的情况。

此后,当leader与follower同步日志的时候,leader会发送自身的日志index,follower判断是否与自己的相符,如果不相符,index–再次同步,直至相符,然后follower合并leader的日志。

配置变更

如果集群节点增加了,如果集群节点不能一起知晓的话,可能出现,一部分不知晓节点变化的节点选出一个leader,另一部分知道节点变化的节点,选出另一个leader。
为了解决这个问题,Raft提出了两种解决方案:
1. 每次只增加一个节点,知道整个集群都知道节点数变化后再增加。
2. 存在一种中间配置的概念,该中间配置下选举leader,需要新配置和旧配置都通过才行。新配置在leader节点配好,leader将中间配置写入日志,广播给其他节点,遵循多数同意即提交的原则。在中间配置未提交的时候,集群按照旧配置做决定,得知有中间配置的节点,使用中间配置运行。当中间配置已提交的时候,整个集群按照中间配置运行,同时有旧配置的节点,按照旧配置运行。在中间配置提交之后,leader再写入新配置的日志,广播给其他节点。当新配置被集群提交之后,整个集群按照新配置运行。

参考

  1. Raft 实现日志复制同步
  2. raft理解

猜你喜欢

转载自blog.csdn.net/lqadam/article/details/79517758