Raft 配置变更 Configuration Changes
说白了,就是动态增减服务器。
假设,一个 Raft 服务器集群的数量刚开始是 3 台,过了 2 个月,由于要搞类似 618,双11 大促,领导要增加系统可用性,那么就要增加到 5 台。
如果增加到 5 台,就带来了配置的变化,首当其冲的,就是 “服务器数量” 这个配置的变化,例如这个配置叫做 “server_count = 3”, 你需要将配置改成 “server_count = 5”。同时,每台服务器还需要知道其他 4 台服务器的 ip + port,这个配置实际上也是需要变化的。
并且,你需要在不停机的情况下,将新的 2 台服务器增加,并且将这些配置应用到另外 3 台旧的服务器上。
这个时候,你该怎么做?
假设是我,我会先将新的 2 台服务器配置完毕(新的配置)再启动。然后,将新的配置发送到旧的 3 台服务器。那 3 台服务器如果成功收到并提交了这个配置,使这个配置生效,那么整个集群的状态就一致了。
很完美。
但是,分布式肯定没有这么简单。假设,在成功启动 2 台新服务器后,老的集群发生了故障,重新开始选举,这个时候,是怎么样子的?
看下图:
上图中,一共有 5 台服务器,S1,S2,S3 代表旧的服务器,S4,S5 代表着新的服务器。
绿色代表旧的配置,蓝色代表新的配置。
我们模拟一下:
- 我们先启动了 S4 和 S5,成功启动。
- 然后我们将新的配置发送到 S1,S2,S3 中,试图让他们应用新的配置。
- 在某个时刻,S3 成功应用新的配置,同时,旧的系统发生了故障,并开始选举。
- 5 台服务器一起开始选举,由于 S1 和 S2 还没有应用新的配置,所以,S1 和 S2 仍然以为只有 3 台服务器,并且在得到 2 张选票后,成功选出一个领导者;
- 而 S3,S4,S5 应用了新的配置,并且获得 3 台服务器的认可,也成功选出了领导人。
- 此时,整个系统出现了 2 个领导人。
那么,是哪里出现了问题呢?
根本原因在于,在同一时刻,有 2 份配置生效了!!!
自然就可以选出 2 个领导人。
所以,要防止这个问题发生,必须不能让 2 份配置同时生效。
Raft 的实现
Raft 是怎么做的呢?
Raft 使用了一种 2 阶段提交的方案。
具体见下图:
第一阶段:
- 发送新配置到旧服务器的 leader。leader 不会直接存储
新配置
,而是存储旧配置 + 新配置
。同时,一旦这个配置被提交(成功同步到新旧集群的大部分跟随者中),那么,所有服务器必须用这个配置来做决定。也就是说,旧配置失效了,不能拿旧配置做任何决定,同时,此时的系统状态是一致的。这个状态称之为共同一致。
第二阶段:
- 当
旧配置 + 新配置
被成功提交,这个时候,leader 会创建一条新配置
复制到 followers 中。从而完成配置变更。
从上图和上文的解释可以看出,这里不会出现新配置
和 旧配置
同时出现的场景。因为他们都被融合在了 旧配置 + 新配置
中去了。即将两个配置融合成一个配置。
那么,图 1 的问题——同时有 2 个 leader 的问题就解决了。
思考:共同一致能确保没有问题吗?
简化起见,我将 新配置 + 旧配置
称之为 共同配置
。
为了阅读方便,我将 旧配置
称之为 old 配置
,将新配置
称之为 new 配置
从图 2 可以看出,一共有 2 个关键的节点:
- 提交 “共同配置”
- 提交“new 配置”
如果这个两个地方出现问题了,怎么办?
假设: 共同配置
提交失败,会怎么样?例如提交的时候,老的 leader 崩溃了。
这要分 2 种情况来看:
1.新 leader 已经收到 “共同配置”,那么新 leader 将继续进行配置变更操作。
2. 新 leader 没有收到 “共同配置”,自然使用 old 配置。
假设:new 配置提交失败,会怎么样?例如提交的时候,leader 崩溃了。
这要看 new 配置有没有同步到大部分节点。
- 假设已经同步到大部分节点,则集群使用“新配置” —— 完成配置变更。
- 假设没有同步到大部分节点,则集群使用 “共同配置”,继续进行配置变更。
另一个问题:共同一致阶段,如果 leader 崩溃,使用什么策略进行选举?
答:如果 共同配置 被应用了,那么,由于领导人完全特性(如果某条日志在某个任期号中已经被提交,那那个条目必然出现在更大任期号的所有领导人中
),新的 leader 必然拥有 共同配置。
如下图:
最后,Raft 论文提出的 3 个问题
1. 新的服务器在初始化时,没有存储任何日志条目。
这个带来的问题是:由于没有存储任何日志条目,那么,就需要时间来补充日志条目,这实际上,是会影响可用性的。
Raft 使用了一种方法来避免:这个阶段的服务器是没有投票权力的。只有当器补充完日志条目了,才会加入集群。
2. 集群的领导人可能不是新配置的一员
什么意思?
答: 当旧集群的 leader 提交了新配置,Leader 需要变成 follower。
为什么?
答:当新的配置生效时,旧 leader 还使用的老的配置,例如新配置的服务器数量是 5 台,而老的 leader 仍然应用的是 3 台服务器。
新集群应该使用新的配置重新进行选举(不然使用新配置干嘛?)。
3. 移除不在新配置
中的服务器可能会扰乱集群
当移除他们时,他们会重新进行选举,导致当前 leader 回退到 follower 状态。虽然新的 leader 会被选出来,但被移除的服务器会再次请求重新选举,循环反复,影响可用性。
Raft 的解决方式:
- 当节点确认当前领导人存在时,则忽略请求投票的 RPC 请求。
- 当节点在最小选举超时时间里收到请求投票请求,他不会更新当前的任期号或者投出选票(从而扰乱集群)。
参考
Raft paper 中文翻译 —— 寻找一种易于理解的一致性算法(扩展版)
EOF