一个关于 Raft 协议的疑问

2020-07-02 08:57:39 +08:00
 phpcyy

如果有 A 、B 、C 、D 、E 一共 5 个节点,A 是 Leader 。 原本的 logIndex 都是 3,如果 A 发送了 4 的日志,B 、C 确认,获得多数 ack,会返回 client 成功。

第一个问题: 这时候如果 Leader 挂掉,B 、C 还没来得及接收下次心跳进入 committed 状态,4 这条日志仍然能保存成功吗?

第二个问题: 如果这时候 A 、B 挂掉,4 这条日志还能确保可以成功保存吗?

最近在看 Raft 相关文章,都没理解上边的这个情况该如何处理,所以求教大家,不胜感激。

我的理解是第一种情况,需要获得多数节点 4 这条日志的状态,B 、C 加上必然存在该消息的 Leader,可以过半,因此可以保存成功。

第二种情况看起来系统已经不能正常工作了,无法确认这条 uncommited 的消息是否需要保存。

4526 次点击
所在节点    程序员
42 条回复
ZingLix
2020-07-02 11:43:56 +08:00
@phpcyy 我一直理解的是日志提交的条件是被多数结点 append,而不是 Leader 将其 commit 。一旦满足就一定会在之后某个时刻把 commit 通知到所有节点上去。
client 在请求后,Leader 挂了没有响应似乎的确可能发生,但正确性还是在的。
fishofcat
2020-07-02 11:46:31 +08:00
5 个节点有三个节点有数据,那么 A 挂了肯定 b,c 选,如果 a,b 挂了,这时候投票原则还是 c 会被选出来,因为 logindex 最大,c 会把数据同步到其它节点。

这时候其实关心的主要问题应该是,a 挂了,a 也没有给 client 回复消息,这时候怎么办?用户如果再次请求,服务端怎么办?(幂等性),如果客户端不请求了,这个数据也会被添加到 log 里面,这时候咋办??
sunznx
2020-07-02 11:48:56 +08:00
接下来的选举中,C 一定可以成为 leader 。只剩下 3 个节点,这些节点要想成为 leader,就必须获得 >= 3 的节点同意,只有 C 有最完整的 log,所以一定是 C 当选,Term 也跟着变了
phpcyy
2020-07-02 11:51:30 +08:00
@noogler67 没错,你说的都对,特别感谢。不过要澄清一点,我提出问题二的原因是,如果 B 没收到 4,C 收到了 4,C 当选 Leader 并提交了这条日志,但是 A 之前未收到多数并没有提交,也就是 client 并不知道这条日志已经提交了,感觉不太合逻辑,所以才会有这个疑问。
phpcyy
2020-07-02 11:58:50 +08:00
@fishofcat 对啊,我现在的主要问题点变成了你这个问题,客户端不知道集群已经执行了该命令,该怎么办
lllllIIIlll
2020-07-02 13:02:35 +08:00
@phpcyy 但 client 可能收不到响应,不知道是不是这样?
----------------------------------------------------------------
这个应该是属于上层实现的问题了,raft 应该不保证这一点。无论是哪一任 leader commit 一个 log 应该都可以有办法通知到上层,Mit6.824 应该是用一个 apply channel 来通知的。但是如果客户端超时错过了通知怎么办,应该取决于应用的实现了。可以参考一下具体的实现,比如 tikv 。
noogler67
2020-07-02 13:07:47 +08:00
client 继续请求 C 的话,C 本身会把 log 复制给别的机器。等 C 复制超过一半机器,就会给 client 返回 commit 成功的消息。
noogler67
2020-07-02 13:09:16 +08:00
每一条 log 可以记录 client 的请求的序列号 id 。可以知道是 client 的之前的那条请求。
noogler67
2020-07-02 13:16:03 +08:00
如果 client 超时中断请求,那 client 就不知道后续状态了。
如果 client 超时,继续请求,client 就能知道状态。根据 raft 协议的话,认为 raft 集群不会挂的情况下,client 应该选择不懈地请求直到 commit 。6.824 lab 中是这样做的。
fishofcat
2020-07-02 13:35:21 +08:00
@noogler67 不用等继续请求的,只要选出主来,c 就会用自己的 term append 一个本 term 的空 entry,老的也会被一起 append 上,其它的解释是对的。client 端一般是要求要重试的。像支付失败,如果 client 端断网,那么你也会收到短信。
wqlin
2020-07-02 13:57:53 +08:00
我觉得大前提不对,需要日志 committed + apply 才会返回给 client 。
第一个问题的话可能会保存成功,也有可能不会(取决于 B/C 是否成功当选)
第二个问题的话比较难了。
Raft 中只有 committed 的日志才是安全不丢的( index <= committed index ),其他情况下都是不安全的。
一家之言,仅供参考
wqlin
2020-07-02 13:59:03 +08:00
保存不代表已经 committed 了,一切以 leader 日志为准
phpcyy
2020-07-02 14:05:21 +08:00
@fishofcat 如果一个命令 client 提交了,然后 client 连接的 leader 宕机,该消息可能成功也可能失败;只要该日志在 leader 宕机之前发给了其他节点,其他节点中的有该最新日志的一台会当选为新的 leader,该命令执行成功;如果在宕机之前没有发给其他节点,该命令不会出现在其他节点,该命令会执行失败。

所以需要依赖具体应用的实现去让客户端在失败时去请求集群,获取之前命令是否执行成功。
phpcyy
2020-07-02 14:10:13 +08:00
@wqlin 你说的是对的,我省略了一些步骤,就是返回 client 成功的时候一定是 commited + applied 的。

我提出问题的时候想的是其他节点并不知道 Leader 已经 commited 且 applied,所以如何判断是否保存之前处于 uncommited 的消息。

现在看来是他们会由于日志更新而当选 Leader,并将该消息 commit 且 apply 。
wqlin
2020-07-02 14:17:11 +08:00
@phpcyy 你忽略了一个前提。leader 要 committed 的话,一定要集群多数派都收到了日志并且 ack 了。这种情况下才能 committed 。
日志 committed 之后就算原 leader 挂掉了,其他节点还会有日志。并且按照 raft 的选举条件,也是拥有最多 committed 日志的节点当选
phpcyy
2020-07-02 14:20:53 +08:00
@wqlin 已经 commited 的日志一定是不会丢的,因为多数节点已经接收到了日志,所以只要这个系统还在工作,这个日志一定还是会在新的 Leader 上的。我之前的疑问是,一些老 Leader 没有 commit 的消息,其他节点也可能会将其 commit,因为他们无法区分老 Leader 是否提交了该日志。
Caskia
2020-07-02 16:21:25 +08:00
@phpcyy 第二问题 @noogler67 解释的很清楚,client 会在超时之前等待这次操作的结果,也就是说就算选举出了新的 leader,那么新的 leader 也会告诉 client 这次操作 committed 。这里有个你忽视的地方,你认为 client 请求 leader1 的时候,leader1 挂掉了,此时 client 就认为失败了,然后会有一个超时时间差,在这段时间里,新的 leader 会把结果告诉 client,在实践的时候是看的集群挂掉了才是真的失败。
diveIntoWork
2020-07-02 17:33:59 +08:00
多数 ack 的 log,是一定不会丢的,这个是 raft 的 leader 完整性约束保证的
NoobPhper
2020-07-02 18:00:49 +08:00
有点乱:

你屡屡思路, 如果 A 挂 理想状态 BCD 任何一个都没有发生 P,那么 BCD 收到了 Leader 的 apply 请求,并且 Ack 了,那么 4 这条日志肯定不会丢鸭

还有 leader 挂了, 客户端立马就知道了,这个时候应该是客户端重试, 重试又会有新的 revision, 不复杂,复杂的是
leader 挂了,然后极端情况下 bcd 出现了 P, 场景复杂很多,建议看下 etcd 的 文档将了一部分这些东西
wqlin
2020-07-03 10:04:24 +08:00
@phpcyy 只有 leader 能 commit 。。老 leader 不知道 commit,然后其他节点 commit 了。这种情况下只能是老 leader 要么挂掉了要么成为 follower 了,总之已经有新 leader 了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/686420

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX