什么是 Raft 算法

Raft 是一种分布式一致性算法,专门用于管理复制日志系统。它由 Diego Ongaro 和 John Ousterhout 在2014年提出,目的是提供一种比传统 Paxos 算法更易于理解和实现的替代方案。

与 Paxos 的对比

Raft 提供与 Paxos 相同的功能和性能保证,但在算法结构和实现方式上有显著不同:

  • 更加模块化:将复杂问题分解为多个独立子问题
  • 更直观:通过明确的角色划分和状态转换简化理解
  • 更适合工程实现:提供了完整的算法细节,而非理论框架

Raft 的核心模块

Raft 将一致性算法分解为三个关键模块:

1. 领导人选举(Leader Election)

  • 集群中任何时候最多只能有一个有效的领导者
  • 节点分为三种角色:领导者(Leader)、跟随者(Follower)和候选人(Candidate)
  • 选举过程使用随机超时机制来避免投票分裂

2. 日志复制(Log Replication)

  • 领导者接收客户端请求并写入日志
  • 领导者将日志条目复制到所有跟随者节点
  • 当多数节点确认接收日志后,该日志被视为已提交
  • 已提交的日志最终会被所有节点应用

3. 安全性(Safety)

  • 选举限制:只有包含所有已提交日志的节点才能成为领导者
  • 日志匹配特性:如果两个日志在相同索引位置有相同任期,那么它们完全相同
  • 状态机安全特性:一旦日志条目在某台服务器上被应用,其他服务器不能在相同索引位置应用不同的命令

Raft 算法的两阶段运行

第一阶段:选举过程

  1. 初始所有节点都是跟随者状态
  2. 跟随者在选举超时(通常150-300ms)后未收到领导者心跳,转变为候选人
  3. 候选人发起选举,向其他节点请求投票
  4. 获得多数票的候选人成为新领导者
  5. 新领导者开始向跟随者发送心跳维持权威

第二阶段:正常操作

  • 领导者处理所有客户端请求
  • 每个客户端请求首先被记录为日志条目
  • 领导者并行地将日志复制到跟随者节点
  • 当日志被复制到多数节点后,领导者应用该日志并通知跟随者应用
  • 领导者定期发送心跳(通常每50ms)来维持领导地位

实际应用场景

Raft 算法广泛应用于各种分布式系统,包括:

  • 分布式键值存储(如etcd、Consul)
  • 分布式数据库(如CockroachDB、TiDB)
  • 容器编排系统(如Kubernetes)
  • 区块链共识机制

领导人Leader选举

Raft 通过选举一个领导人,然后给予他全部的管理复制日志的责任来实现一致性。

在Raft中,任何时候一个服务器都可以扮演下面的角色之一:

  • 领导者Leader:处理客户端交互,日志复制等动作,一般一次只有一个领导者
  • 候选者Condidate:候选者就是选举过程中提名自己的实体,一旦选举成功,则成为领导者
  • 跟随者Follower:类似选民,完全被动的角色,这样的服务器等待被通知投票

而影响他们身份变化的则是选举。

Raft 使用心跳机制来触发选举,当Server启动的时候,初始状态都是 Follower。每一个Server都有一个定时器,超时时间为 Election timeout (一般为150-300ms),如果某Server没有超时的情况下收到自领导者或者候选者的任何消息,定时器重启,如果超时,它就开始一次选举。

节点异常类型及处理机制

Leader 不可用

当集群中的Leader节点发生故障时,会导致整个集群暂时无法处理写请求。这种情况可能由以下原因引起:

  1. 服务器硬件故障(如CPU过载、内存耗尽)
  2. 网络分区导致Leader与其他节点失去连接
  3. Leader进程崩溃或被强制终止

典型处理流程

  1. Follower节点检测到与Leader的心跳超时(通常设置150-300ms的超时阈值)
  2. Follower转为Candidate状态并开始新一轮选举
  3. 新Leader选举成功后接管集群管理权

当一段时间之后,如果之前的Leader再次加入集群,则两个Leader比较彼此的步进数,步进数低的Leader将切换自己的状态为 Follower。较早前 Leader 中不一致的日志将被清除,并与现有的Leader中的日志保持一致。

Follower 不可用

当部分Follower节点失效时,集群仍能保持基本运作,但会影响数据复制的一致性。常见场景包括:

  • 短暂网络抖动导致Follower暂时失联
  • Follower节点磁盘空间不足无法写入日志
  • 配置错误导致Follower无法加入集群

恢复策略

  1. Leader持续尝试与Follower建立连接
  2. 当Follower恢复后,通过日志复制追赶最新状态
  3. 若长期无法恢复,可能触发自动节点替换机制

Follower 节点不可用的情况相对容易解决,因为集群中的日志内容始终是从Leader节点同步的,只要这一节点再次加入集群时重新从Leader节点处复制日志即可。

选举冲突(多个Candidate/Leader)

在特定网络条件下可能出现选举异常:

  1. 网络分区导致不同分区各自选举出Leader
  2. 选举超时设置不合理导致频繁选举
  3. 节点时钟不同步影响选举逻辑

解决方案

  • 采用PreVote机制防止频繁选举
  • 设置合理的选举超时参数(建议Follower超时为Leader的2-3倍)
  • 实现任期(Term)机制确保只有一个合法Leader

在集群中出现多个 Candidate 或 多个Leader通常是由于数据传输不畅造成的,出现多个Leader的情况相对少见,但多个 Candidate 比较容易出现在集群节点启动初期尚未选出Leader的混沌时期。

Candidate 继续向其他的 Follower 询问。由于一些 Follower 已经投过票了,所以均返回拒绝接受。在步进数相同的情况下,Candidate 将拒绝接受另一个 Candidate 的请求。由于第一次未选出 Leader,Candidate 将随机选择一个等待间隔(150ms-300ms)再次发起投票。

如果得到集群中的半数以上的Follower的接受,这一Candidate将成为Leader。在被多数节点拒绝之后,并已知集群中存在 Leader后,这一Candidate 节点被终止投票请求、切换为Follower,从Leader节点同步日志。

新节点加入集群

集群扩容时新节点加入需要特殊处理:

1. 配置阶段

  • 准备新节点硬件资源
  • 安装相同的服务软件版本
  • 配置初始集群信息

2. 加入流程

  • 新节点以Learner模式启动
  • 从Leader同步完整状态数据
  • 达到同步阈值后转为正式Follower

3. 数据同步策略

  • 快照传输(适用于大状态)
  • 增量日志复制
  • 一致性检查机制