理解Raft协议

1. 引言

一致性算法的目的是让集群工作的像一个整体,即使部分宕机依然对外提供一致的结果。

在Raft出现之前,Paxos算法是主流的一致性算法,常见的一致性框架,要么是基于Paxos,要么深受Paxos影响,比如Zookeeper。不过Paxos理解起来复杂,Paxos理论和真正的实现还有一定的空白,导致实现更为困难。

Raft一开始的目标就是提供一个比Paxos更容易理解,更方便实现的一致性算法。为此Raft将算法分解为3部分: 领导选举(leader selection)、 日志复制(log replication)、 安全性(safety), 并且减少内部状态。

Raft算法和Paxos很相似,但额外提供了几个特性:

  • 强领导者(strong leader),日志同步只能从领导者发往到其他节点
  • 领导选举(leader selection),使用随机定时器来发起选举领导者,减少冲突的可能。
  • 成员变化(membership change)

本文主要涵盖如下内容:

  1. 复制状态机(replicated state machine)
  2. Paxos的缺点
  3. 提升理解性的方法
  4. Raft一致性方法
  5. 评价Raft算法
  6. 相关工作
1. 复制状态机(Replicated State Machine)

复制状态机用于在一组服务器提供一致的状态副本,即使部分服务器崩溃,这组服务器仍然能对外提供一致的状态。
在这里插入图片描述

复制状态机在分布式系统在多用于解决有关容错的问题。许多系统都需要单一的领导者,如HDFS、 GFS等,使用单独的复制状态机,来完成领导者选举、存储配置信息来应对领导者崩溃。最常见的复制状态机实现有Chubby、 Zookeeper等。

复制状态机使用类使用MySQL的主从同步机制,通过操作日志实现数据复制, 每一条操作日志里包含一定的动作,状态机在副本节点按顺序执行日志, 相同的初始状态,经过了相同的操作,最终一定会得到相同的结果。

如何保证日志复制过程的一致性就是一致性算法的工作。

在工程实践中使用的一致性算法,一般有以下特性:

  • 确保安全性(不会返回一个错误结果), 非拜占庭问题,要考虑网络延迟、分区、丢包、冗余、乱序
  • 高可用,集群中大部分机器可用,集群就可用
  • 不依赖于时钟来保证时序
  • 数据写入耗时,取决于集群中写入较快的大部分(N/2+1台),而不是最慢的那一台
2. Paxos的不足

Paxos首先定义了一个能够达成单一决策的一致性协议,我们把它叫做单一决策Paxos(single-decree Paxos), 之后通过组合多个单一决策Paxos来完成一系列的决策,如一个日志。

Paxos有两个致命的缺点:

  • 不好理解,单一决策的解释比较晦涩,多决策通过单一决策实现,又额外添加了复杂性
  • 难以实现,Paxos论文里详细介绍了单决策部分的逻辑,而多决策仅仅介绍了可能的方法,具体实现和算法的论文之间有巨大的鸿沟
3. 易于理解的设计

Raft的设计目标:

  • 完整的理论基础,供实际系统实现
  • 所有情况下保证安全可用
  • 常规操作必须高效
  • 易于理解,让大部分开发者都能理解

通过两种方式提高可理解性:

  1. 将问题分解, Raft将问题分解为: 领导选举、日志复制、安全、成员变化
  2. 减少需要考虑的状态数量
4. Raft一致性算法

Raft实现中将节点分为3种角色: Leader、Follower、Candidate
在这里插入图片描述

4.1 服务器存储的状态

所有服务器持久存储:

名称描述
currentTerm服务器最后知道的任期号(从 0 开始递增)
votedFor在当前任期内收到选票的候选人 id(如果没有就为 null)
log[]日志条目;每个条目包含状态机的要执行命令和从领导人处收到时的任期号

所有服务器不稳定存储:

名称描述
commitIndex已知的被提交的最大日志条目的索引值(从 0 开始递增)
lastApplied被状态机执行的最大日志条目的索引值(从 0 开始递增)

leader不稳定存储

名称描述
nextIndex[]对于每一个服务器,记录需要发给它的下一个日志条目的索引(初始化为领导人上一条日志的索引值 +1)
matchIndex[]对于每一个服务器,记录已经复制到该服务器的日志的最高索引值(从 0 开始递增)
4.2 日志分发RPC (Append Entries RPC)

由leader发起,负责分发日志到所有的Follower服务器, 这个RPC同时也用做心跳包。

参数描述
term领导人的任期号
leaderId领导人的 id,为了其他服务器能重定向到客户端
prevLogIndex最新日志之前的日志的索引值
prevLogTerm最新日志之前的日志的领导人任期号
entries[]将要存储的日志条目(表示 heartbeat 时为空,有时会为了效率发送超过一条)
leaderCommit领导人提交的日志条目索引值
返回值描述
term当前的任期号,用于领导人更新自己的任期号
success如果其它服务器包含能够匹配上 prevLogIndex 和 prevLogTerm 的日志时为真

Follower实现:

  • 如果term < currentTerm, 返回success=false
  • 如果本机log数组下,log[prevLogIndex]不存在或者log[prevLogIndex]的任期号和prevLogTerm不匹配,返回success=false
  • 如果log里存在一条日志,在prevLogIndex之后,且和entries对应位置的日志,任期号不匹配,则删除log在该位置之后的所有日志
  • 添加任何在entris里,然后log数组相应位置不存在的日志
  • 如果leaderCommit > commitIndex ,将commintIndex设置为leaderCommit并执行对应日志
4.3 投票请求 (RequestVote RPC)

候选人发起投票请求

参数描述
term候选人的任期号
candidateId请求投票的候选人 id
lastLogIndex候选人最新日志条目的索引值
lastLogTerm候选人最新日志条目对应的任期号
返回值描述
term目前的任期号,用于候选人更新自己
voteGranted如果候选人收到选票为 true

接受者实现:

  • 如果term < currentTerm, 返回false
  • 如果候选人日志没有自己新,返回false
  • 如果votedFor为空或者candidateId和votedFor相同,则投票给该候选人
  • 如果term > currentTerm,将votedFor置为candidateId,投票给该候选人
4.4 服务器遵循的规则

所有服务器

  • 如果commitedIndex > lastApplied, lastApplied自增, 将log[lastApplied]应用到状态机
  • 如果RPC请求或响应的term > currentTerm, 将currentTerm设置为term, 把自己切换为Follower

Follower

  • 响应AppendEntries RPC和RequesteVote RPC
  • 如果超时没有收到AppendEntries RPC和RequestVote RPC,将自己转换为候选人

候选人

  • 转变为候选人后发起选举
    • currentTerm自增
    • 给自己投票
    • 重置选举计时器 (用于统计选举超时)
    • 向其他服务器发送RequestVote RPC (也就是每台机器都需要知道其他所有的服务,引擎状态机集群是不能动态添加的)
  • 如果收到多数节点的投票,成为领导人
  • 如果收到新leader的AppendEntries RPC,将自己转换为Follower
  • 如果选举超时,开始新一轮选举

leader

  • 一旦成为leader,向所有服务器发送AppendEntries请求,即使没有日志也定期发送做为心跳
  • 收到客户端请求,向本地log数据写入日志,在日志被commit之后,应用到状态机,然后响应客户端
  • 向Follower(假设机器index是i)发送leader的log下nextIndex[i]到log.length间的所有日志
    • 如果发送成功,nextIndex[i]和matchIndex[i]都设置为log.length
    • 如果发送失败
      • 如果响应的term大于currentTerm, 将自己转换为Follower
      • 说明同步失败是因为log的prevLogIndex和prevLogTerm不匹配,将nextIndex[i]递减
  • 如果存在N
    • currentTerm == log[N].term,保证这条日志是当前leader写入的日志
    • 且matchIndx里多数节点的值 > N,大多数节点已经接收该日志
    • 且N > commitIndex, 这个时候将commitIndex设置为N
4.5 Raft算法总结
性质描述
选举安全原则
Election Safety
一个任期(term)内最多允许有一个领导人被选上(5.2 节)
领导人只增加原则
Leader Append-Only
领导人永远不会覆盖或者删除自己的日志,它只会增加条目
日志匹配原则
Log Matching
如果两个日志在相同的索引位置上的日志条目的任期号相同,
那么我们就认为这个日志从头到这个索引位置之间的条目完全相同(5.3 节)
领导人完全原则
Leader Completeness
如果一个日志条目在一个给定任期内被提交,
那么这个条目一定会出现在所有任期号更大的领导人中
状态机安全原则
State Machine Safety
如果一个服务器已经将给定索引位置的日志条目应用到状态机中,
则所有其他服务器不会在该索引位置应用不同的条目(5.4.3 节)

参考资料
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值