use*_*874 13 algorithm distributed-computing distributed-system
假设发生网络分区并且领导者 A 占少数。Raft 会选出一个新的领导者 B,但 A 认为它仍然是领导者一段时间。我们有两个客户。客户端 1 将键/值对写入 B,然后客户端 2 在 A 下台之前从 A 读取键。因为 A 仍然相信它是领导者,所以它会返回陈旧的数据。
原论文说:
其次,领导者必须在处理只读请求之前检查它是否已被废黜(如果选举了最近的领导者,则其信息可能会过时)。Raft 通过在响应只读请求之前让领导者与集群的大多数人交换心跳消息来处理这个问题。
是不是太贵了?领导者必须为每个读取请求与多数节点交谈?
我很惊讶答案中有这么多模棱两可,因为这是众所周知的:
是的,要从 Raft 获得线性化读取,您必须通过仲裁来回。
这里没有捷径。事实上,etcd 和 Consul 在他们的 Raft 实现中都犯了错误并导致了线性化违规。实现者错误地认为(就像很多人一样,包括我自己)如果一个节点认为自己是领导者,那么它就是领导者。
Raft 根本不保证这一点。一个节点可以是一个领导者,并且不会因为网络分区导致其他人首先站出来而了解它失去领导权。因为在分布式系统文献中时钟误差被认为是无界的,所以再多的等待也无法解决这种竞争条件。新领导不能简单地“等待”然后决定“好吧,老领导现在肯定已经意识到了”。这只是典型的租约锁定内容 - 您不能使用具有无限错误的时钟来做出分布式决策。
Jepsen 介绍了这个错误细节,但要引用结论:
[有]三种类型的读取,用于不同的性能/正确性需求:
- 任何事情都可以读取,其中任何节点都可以以其最后一个已知值进行响应。在 CAP 意义上完全可用,但不能保证单调性。Etcd 默认执行此操作,Consul 将其称为“陈旧”。
- 大多数是一致的读取,只有领导者可以响应,并且偶尔允许过时的读取。这就是 etcd 目前所说的“一致”,也是 Consul 默认所做的。
- 一致性读取,这需要往返延迟,以便领导者可以在响应之前确认它仍然具有权威性。Consul 现在称之为一致。
为了与文献中的其他一些结果相结合,这个问题正是 Flexible Paxos 表明它可以处理的事情之一。FPaxos 中的关键实现是您有两个法定人数:一个用于领导选举,另一个用于复制。唯一的要求是这些法定人数相交,虽然多数法定人数可以保证这样做,但它不是唯一的配置。
例如,可以要求每个节点都参与领导选举。这次选举的获胜者可能是唯一一个服务请求的节点——现在这个节点在本地提供读取服务是安全的,因为它知道一个新的领导者来加强领导层法定人数需要包括自己。(当然,权衡是如果这个节点宕机了,你就无法选举新的领导者!)
FPaxos 的重点是,这是您必须做出的工程权衡。
领导者不必针对每个读取请求与大多数人交谈。相反,当它不断地与同伴进行心跳时,它会保持一种陈旧性衡量标准:自从收到法定人数的同意以来已经过去了多长时间?领导者将检查此陈旧性度量并返回 StalenessExceeded 错误。这使调用系统有机会连接到另一台主机。
最好将陈旧性检查推送到调用系统;让低级别的筏系统具有更高的可用性(在 CAP 术语中),并让调用系统决定在什么陈旧级别进行故障转移。这可以通过多种方式来完成。您可以让调用系统向 raft 系统发出心跳,但我最喜欢的是在响应中返回陈旧性度量。当客户端在请求中包含其时间戳、raft 服务器在响应中回显它并且客户端将往返时间添加到 raft 陈旧性时,最后一个可以得到改进。(注意:始终使用纳米时钟来测量时间差,因为它不会像系统时钟那样倒退。)