LJ的Blog

学海无涯苦做舟

0%

Raft(翻译)

Raft(可理解的分布式共识)

所以,什么是分布式共识?

让我们以一个栗子开始…

假设我们有一个单节点系统,在这个栗子中,你可以认为我们的节点是一个存储单个值的数据库,我们还有一个可以向服务端发送值的客户端,在单节点上很容易就这个值达成一致或共识。

但是我们如何在多节点上达成共识?

这就是分布式共识的问题

Raft 是一个实现分布式共识的协议,让我们看一下他是如何工作的高级概述。

一个节点可能三个状态中的一种:

  • Follower 状态
  • Candidate 状态(候选状态)
  • Leader 状态

所有的节点都以 Follower 状态开始,如果 followers 没有收到 leader 的消息,那么他可以变成 candidate,然后 candidate 向其他节点请求投票,节点会投票回复。如果 candidate 获取了大多数节点的投票那么他会变成一个 leader。这个过程被称为 Leader 选举。所有对系统的更改都需要经过 leader,每次更改都作为一个条目添加到节点日志中。日志未提交不会更改节点的值,为了提交这个条目首先会复制这个值并发送给 follower 节点,然后 leader 等到大多数节点都已经写入条目才会更改这个值,接着 leader 会通知 followers 条目已经被提交了。

集群已经就系统状态达成共识,这个过程被称为日志复制(Log Replication)。

Leader 选举

在 Raft 中有两种超时设置控制选举:

  • 首先是election timeout(选举超时):选举超时是 follower 等待直到成为 candidate 的时间,选举超时随机随机设置在 150ms ~ 300ms 之间。在选举超时后,follower 成为 candidate 并开启新的选举期,然后自己为自己投票。向其他节点发起投票请求,如果接收节点在此期间还没有投过票,那么他会投票给此候选者并重置自己的选举超时。一旦 candidate 获取大部分投票就会成为 leader。
  • 然后是心跳超时(hearbeat timeout):Leader 开始向 followers 发送 Append Entries message,这些消息按心跳超时指定的时间间隔发送,followers 响应每一条 Append Entries message。此次选举任期将持续到 follower 停止接收心跳并成为候选人。要求多数票保证每届只能选举一个 leader,如果两个节点同时成为 candidate 则会发生投票分裂。

日志复制

一旦选举出 leader,需要将系统所有更改复制到所有节点。这可以通过同样在心跳上使用的 Append Entries message 完成。通过栗子看一下这个过程:

  • 首先客户端向 leader 发送一个变更
  • 变更追加到 leader 的日志
  • 然后变更在下次心跳被发送到 follower 中
  • 一旦大多数 follower 承认他,一个 entry 将会被提交
  • leader 发送响应到客户端

Raft 甚至在面对网络分区(network partitions,分布式系统通常由多个节点构成,由于网络是不可靠的,所以存在分布式集群中的节点因为网络通信故障导致被孤立成一个个小集群的可能性,即网络分区)保持一致。栗子:

有 A、B、C、D、E 五个节点,A、B 和 CDE 因故失联,此时 B 和 C 分别为各自分区的 Leader

由于分区,现在有两个不同任期的的 leader,client 1 尝试将节点 B 的值置为 3,节点 B 不能(将日志)复制到大部分节点上,所以他的 entry 保持未提交(uncommitted)。

client 2 尝试将节点 C 的值置为 8,因为他可以复制到大多数节点上,所以可以成功。当网络分区修复时,节点 B 将看见更高的选举任期然后下台,A 和 B 都将回滚他们未提交的 entries 并匹配新 leader 的日志。现在集群中的日志是一致的了。

可以进一步阅读的资料