写点什么

Raft 一致性协议简说

  • 2022 年 7 月 11 日
  • 本文字数:2315 字

    阅读完需:约 8 分钟

原文来源:https://tidb.net/blog/b34bd29c


数据一致性是在一个需要容错的分布式系统中提出的概念。这里的一致性我们要特别搞清楚,主要有以下两层含义:


  • Raft 系统中所有节点的数据状态最终一致

  • Raft 系统中大部分节点的日志状态实时一致


一直以来一致性算法都是一个高深莫测的领域, 特别是一致性算法的鼻祖 Paxos,以复杂难懂而著称! 然而在耐心研读了raft 的 Paper以后,发现这一领域也并不是那么神秘。首先我想说 raft 的 Paper 质量非常好好!它不仅阐述了复杂的一致性算法,而且展示了一种解释复杂问题的方法。它深刻吸取 Paxo 抽象难懂的教训,在 Paper 中特别强调了 Understandable! 嗯,Understandable, 作者是认真的。 为了证实 Raft 更容易理解和掌握,作者专门组织了一帮大学学生,分为两组,分别学习 Raft 和 Paxos, 然后对学员的掌握情况进行测试,测试结果也以论文形式发出。真是下了不少功夫啊!


这里简单梳理一下 Raft Paper 中的框架内容,若要全面了解 raft 协议,强烈建议读原 Paper.

一、Raft 协议中规定了两种存储

  1. Log

  2. 为保证读写效率,raft 采用了先写日志的原则。一个日志条目包含了对状态机中数据的操作。日志的写入是顺序的,效率较高。 Raft 的 Leader 收到一个操作请求,首先将其 append 到自己的日志,然后将其广播到集群,大多数节点收到这个日志并 Append, 这个日志就是确定可以 Commit 了。 Leader 将这个日志操作在状态机中执行,这样就完成了。

  3. Replicated state machine

  4. 复制状态机中保存的是实际的客户数据,数据的读取都需要从状态机中读。因此 Leader 在返回给 Client 成功时,数据一定要写入状态机,不然会造成 Client 读取不到最新数据。

二、Raft 规定一个节点的三种角色

  1. Leader

  2. Leader 是服务客户端的唯一 server。 Leader 要不断地向 Follower 发送心跳包还确保自己的 Leader 地位。

  3. Candidate

  4. Candidate 是一个临时角色,一般来讲,任何一个节点都不会长时间处于这样一种角色。它是由 Follower 节点转换来的。即当一个 Follower 节点在一定时间 (Election timeout) 没有收到 Leader 的心跳包,这个 Follower 就会转换为 Candidate, 发起投票选举自己为 Leader, 如果它能获取到多数投票,它就会成为下一个任期(term)的 Leader. 若不能,则有两种情况: 继续投票或转换角色为 Follower.

  5. Follower

  6. Follower 角色接受 Leader 的日志复制,负责高可用。当 Leader 挂掉时,其中最先 Election timeout 的 follower 会变为 Candidate, 发起投票选举自己为 leader. 这里的 Election timeout 是一个时间范围内的随机值(Raft Paper 建议 150ms - 300ms.),这样确保不会一直有两个 Candidate 同时选举。 在 TiKV 中 Election timeout 是 10s(如果处于无主状态,大约经过 raft-base-tick-interval default 1s * raft-election-timeout-ticks default 10 时间以后发起选举)

三、Raft 协议使用三种 RPC 来广播信息

  1. AppendEntries RPC

  2. Leader 使用 AppendEntries RPC 来复制日志记录给其它 Followers, 当然心跳包就是一个没有日志记录的 AppendEntries RPC。

  3. RequestVote RPC

  4. Candidate 发送 RequestVote RPC 来发起选举。

  5. InstallSnapshot RPC

  6. 当一个 Follower 角色落后 Leader 太多时,会使用 InstallSnapshot RPC 来使其快速补充数据。任何一个节点都会做日志定期快照。可以参照 Redis 的 Log Rewrite 来理解这里的 snapshot.

四、Raft 协议四大主要活动

  1. Leader election

  2. 集群中的 Server 从 Follower 角色开始,在经历 Election Timeout 周期没有收到 Leader 的心跳时,该 Server 会转换角色为 Candidate, 将自己的任期加 1, 投自己一票,并发送 RequestVote RPC 向集群中的其它 Server 发起投票。如果它能够获得大多数投票,它就会当选为 Leader。当然这里面涉及到许多细节,这里不详细阐述。 Leader election 活动在 Raft 系统中发生的并不频繁。



  1. Log replication/heartbeat

  2. Leader 响应客户端请求,Client 的每一个请求都是对状态机数据的修改。Leader 收到请求后,首先将该命令 Append 到自己的日志中,然后发送 AppendEntry RPC (Heartbeat 也是 AppendEntry RPC 包, 只是里面没有日志) 向集群中的其它节点广播这一操作,当大多数节点收到这一日志时,Leader 就将该日志在状态机中应用(commit), 成功应用后才返回给 Client 成功。如果某个节点没有反馈成功收到这一日志,Leader 会持续不断地向其广播,即使该日志已经成功 Commit 也不会停止,直到其收到为止。当然 Raft 采取了许多措施来保证日志的完整性和一致性。 Log Replication 是 Raft 系统中最频繁的活动,它开始于 Raft 系统启动,终止与整个系统停止。

  3. Membership change

  4. 理解 Raft 成员变更可以参考 MySQL MGR 中的View & ViewChanges. 当集群中某个节点宕机或者添加新的节点到集群时,会触发 Membership change. Raft 采用 Joint Consensus 机制来保证平滑过渡,并且不影响对 Client 请求的处理。这一活动在 Raft 系统中也不常见。

  5. Log compaction

  6. Log 不能无限增长。Raft 会定期对日志做快照(snapshot),这一操作与 Redis 中的 Log Rewrite 类似(如下图)。在实际的实现中,庞大的数据集可能会使日志占有巨大空间,即使经过压缩后,日志量还是很大,还应实现定时清理机制。TiKV 中通过一些参数(如:raft-log-gc-size-limit)设定来控制 Raft Log 的残余量, 超过这一设置会被清理以节省空间。


五、总结

简单来看,上述几个部分包含了 Raft 协议的主要内容。希望对了解 Raft 概貌有些帮助。对细节的阐述往往使问题变得复杂,学习新鲜事物时,我们可以先从全局来看其全貌,将其拆解为几大模块,然后再分别详细研究各个模块的细节,等了解了细节,再从全局来看各各模块之间的关系,直到彻底了解整个系统。


发布于: 刚刚阅读数: 2
用户头像

TiDB 社区官网:https://tidb.net/ 2021.12.15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
Raft一致性协议简说_TiDB 社区干货传送门_InfoQ写作社区