在分布式系统有一个经典的CAP理论,C:一致性,即集群中所有节点都应该是一致的。A:可用性,集群一直处于可用状态。P:分区容错性:即复制所有数据到集群的所有节点,保证即使出现网络分区,不同的网络分区都可以访问到数据,不过这里又要引用出数据一致性。
因为网络始终存在不可靠的可能,所以在P确定的情况下,我们只能从C和A中选择一种,优先选择C。
Raft算法实现的是强一致性,即优先追求数据一致性,若集群无法达到一致性,则应该停止服务。raft使用了“Quorum”机制,只要集群中超过半数节点可以正常运转,集群就可以正常提供服务。同时Raft还使用了该机制来达成共识,即一个操作只要半数节点同意,即可进行。
一般Raft会选举出一个leader(领导)节点,由leader节点负责所有写请求,保证了操作顺序,同时leader会把自己收到请求广播给其他follow节点,从而达成数据一致性。
通过以上描述,我们需要知道的是:
-
如何进行领导选举
集群启动或leader节点下线的时候都需要进行leader选举,此外raft中leader还有任期的概念,每个任期都要选举新的leader。
- raft中节点状态:
- leader:leader节点定时像follower节点发送心跳维护leader地位。
- candidate:follower节点在一段时间没有收到心跳消息后,会转化为candidate(候选)节点,并发起选举流程
- 增加任期,更新currentTerm 为currenTerm+1
- 给自己投上一票
- 向集群其他节点发送报文请求,要求它们给自己投票。
- follower
- 投票实现:
- 其他节点收到candidate节点的投票要求后,会进行如下操作:
- 比较任期,如果candidate的任期比自己小则拒绝
- 比较上一条日志的任期号和索引值,若小于则拒绝
- 如果任期相等,且接收节点的votedFor不为空,说明该任期内已经投过票,拒绝
- 投票,更新任期时间,重置选举超时时间。
- 其他节点收到candidate节点的投票要求后,会进行如下操作:
- candidate节点状态转换:
- 收到超过半数的投票,成为leader节点
- 收到其他节点的心跳报文,且任期不小自己当前的任期,说明已经有leader节点了,转换为follower节点
- 等待一段时间,选举超时或没有收到心跳报文,开始重新选举
- raft中节点状态:
-
日志复制
leader节点会将每个请求记录为一个新的日志条目并加入到本地日志集中,然后通过心跳报文,发送给集群中其他节点,让其复制该条日志条目。因此所谓的数据一致性,其实可以看做成日志的一致性。心跳报文也可看做附加日志报文。
- 日志复制流程:
- follwer节点收到报文以后,首先比对任期值大小,若报文任期小于节点当前任期则拒绝
- 执行日志一致性检查操作,不通过则拒绝
- 检查日志的任期号和索引,一致则相同
- 添加日志报文到本地日志集中,若本地日志集与报文日志有冲突(索引相同,任期不同),则需删除索引及以后的所有日志
- 日志复制流程:
-
数据安全
- 投票限制,如果一个节点不包含所有已提交日志,则不能当选leader节点
- 新的leader节点不会抛弃前一任未提交的日志,而是继续处理。如果一个日志在前一个任期已经被多数节点接受,在现任期中,需等到当前任期的日志被大多数节点接受,才会提交。