Raft 简介
- 论文地址:raft.github.io/raft.pdf
- 开源项目:raft.github.io/
Raft是一个管理日志复制的共识算法,Raft在效率和作用上与Paxos相同,但是易于理解和实现,在TIDB、etcd中均采用了Raft算法。
共识算法允许一组机器作为一个整体来工作,在某些机器发生故障时依然可以正常提供服务。
Raft集群包含若干节点,半数以上的节点有效时,集群可以正常工作。5个节点是经典例子,整个集群可容忍两个节点失效。
Raft 三要素
leader负责管理日志复制。leader从客户端接收日志(log entries),然后把日志复制到其他节点上,来保持多个节点的数据一致性。leader可能会发生故障,这时候需要选举一个新的leader,raft算法可分解为如下三个子问题:
- leader election 领导者选举:当前leader发生故障时,需要选举新的leader
- log replication 日志复制:leader从客户端接收日志,然后复制到集群中的其他节点,并强制要求其他节点的日志和自己保持一致。
- safety 安全性:如果有任何的节点已经应用了一个确定的日志,那么其他的节点不能在同一个日志索引位置应用一个不同的指令。
Leader election 领导者选举
在任何时刻,集群中的节点都处于这三种角色之一:Leader、Follower、Candidate。
正常情况下,只有一个leader,其他都是Follower。只有leader出现故障时,Follower才会变成Candidate,当选举成功后,某个Candidate会变为Leader,其他的节点变为Follower。
如上图所示:Raft把时间分割成任期,每一段任期从一次选举开始。一个任期内只有一个Leader,当需要新的选举时,任期+1。
要开始一次选举,Follower要将任期号+1,并转变为Candidate。然后向集群中的其他节点发送RequestVote RPC,接下来一直保持Candidate状态直到发生以下三件事之一:(a)获得了半数以上的投票,赢得了选举,(b)其他的节点成为了Leader,(c)选举超时
节点投票时同一个任期只能投一次票,所以同一任期内最多只有一个Candidate能获得半数以上的支持
- (a)赢得选举
获得了半数以上的投票,赢得了选举,立即成为Leader,然后向其他节点发送心跳建立自己的权威并阻止新的选举
- (b)其他节点成为了Leader
等待其他节点投票时,这时有别的节点成为了Leader,并收到了AppendEntries RPC,如果Leader的任期号不小于自己当前的任期号,此时会回到Follower,如果RPC的任期号比自己小,那么会拒绝RPC并保持Candidate
- (c)选举超时
如果有多个Follower同时成为了Candidate,选票可能会被瓜分导致没有Candidate能获得半数以上的支持。超时后会增加任期号开始一轮新的选举,每个节点设置了随机超时时间(如150-300ms)避免一直重复选举
log replication 日志复制
leader被选举出来后,他就开始为客户端提供服务。客户端的每个请求都会生成一条日志,leader会发起AppendEntries RPC让其他节点复制日志,当半数以上的节点复制后,leader会提交这条日志,并将执行结果返回给客户端。
当leader崩溃时,其他Follower可能还未完全复制日志,那么新选举出Leader后,怎么保证其他Follwer的日志跟leader一致呢?
AppendEntries RPC会包含最后一个已提交日志的任期号和索引号,如果Follower发现自己找不到相同的条目,就检测到不一致并拒绝RPC。同时Leader会对每一个Follower维护一个nextindex,表示下一个需要发送的日志条目。Leader选举成功后,nextindex会初始化为最后一条日志的index+1。如果Follower的日志和Leader不一致,下一次AppendEntries RPC的一致性检查就会失败,这时Leader会减小nextindex并重试,直到找到发生不一致的位置,然后将Follower的冲突日志全部删除并同步Leader的日志。
通过这种方式,Leader获得权利后,无需关注其他节点跟自己是否一致,在后续的AppendEntries RPC会自动检测不一致并恢复。
安全性
如何保证选举出的leader拥有最全的数据?
- leader会保证日志复制到半数以上的节点,然后才会提交
- leader选举时,RequestVote会包含Candidate的日志信息,节点会拒绝日志没有自己新的投票请求
根据这两个规则,只有拥有最新日志的节点才有可能获得半数以上的节点支持,当选为leader
日志压缩
日志不能无限增长,Raft使用快照方式来实现日志压缩。每个节点独立维护自己的快照,快照中只包含已经被提交的日志以及最后的索引,创建后在最后索引之前的日志和快照都可以被清理了。
总结
虽然Raft算法中说比Paxos算法简单了,但整体看下来复杂度还是挺高的,很想理清楚但感觉写的还是很乱,最终这篇也只是我个人的一些小总结,做个记录,扩展一下视野。