假设发生网络分区且领导者A属于少数群体。筏子将选出一位新的领导者B,但A认为它仍然是领导者一段时间。我们有两个客户。客户端1将键/值对写入B,然后客户端2在A降级之前从A读取密钥。因为A仍然认为它是领导者,它将返回过时的数据。
原始论文说:
其次,领导者必须检查是否已被废.. 在处理只读请求之前(其信息 如果最近的领导人当选,可能会变得陈旧。 Raft通过让领导者交换心跳来处理这个问题 响应之前具有大多数群集的消息 只读请求。
是不是太贵了?领导者必须与每个读取请求的多数节点通信?
答案 0 :(得分:3)
我很惊讶答案如此含糊,因为这是众所周知的:
是的,要从Raft中获取线性化的读数,您必须往返仲裁。
这里没有捷径。实际上,etcd和Consul都在实现Raft的过程中犯了一个错误,并导致线性度违规。实现者错误地相信(就像许多人一样,包括我自己),如果某个节点认为自己是领导者,那它就是领导者。
筏完全不能保证这一点。节点可能是领导者,却没有得知其失去领导权,这是因为网络分区导致其他人首先站起来。由于时钟错误在分布式系统文献中被认为是无限的,因此没有任何等待可以解决这种竞争状况。新领导人不能简单地“等待”,然后决定“好吧,旧领导人必须已经意识到了”。这只是典型的租用锁东西-您不能使用无界错误的时钟来做出分布式决策。
Jepsen covered this error detail,但引用结论:
[存在]三种类型的读取,可满足不同的性能/正确性需求:
- 任何地方都可以读取,其中任何节点都可以使用其最后的已知值进行响应。在CAP的意义上是完全可用的,但不能保证单调性。 Etcd默认情况下会这样做,而Consul将此术语称为“过时”。
- 最一致的阅读,只有领导者才能回应,偶尔也允许过时的阅读。这就是etcd当前所说的“一致”,以及Consul默认情况下所做的事情。
- 一致的读取,这需要往返延迟,以便领导者可以在响应之前确认它仍然是权威的。领事现在称其为一致。
仅仅与文献中的其他结果相结合,这个问题就是Flexible Paxos可以解决的问题之一。 FPaxos中的关键实现是您有两个法定人数:一个用于领导者选举,另一个用于复制。唯一的要求是这些法定人数相交,并且尽管可以确保多数仲裁,但并不是唯一的配置。
例如,可以要求每个节点都参加领导者选举。选举的获胜者可能是服务请求的唯一节点-现在,现在该节点在本地服务读取是安全的,因为它知道要让新领导者加强领导人数,就需要包括自己。 (当然,要权衡的是,如果此节点出现故障,您将无法选举新的领导者!)
FPaxos的要点是,这是您要进行的工程设计上的权衡。
答案 1 :(得分:1)
领导者不必为每个阅读请求与多数人交谈。相反,当它持续与其同行心跳时,它会维持一个陈旧性度量:自从它从法定人数中收到一个好的时间以来已经有多长时间了?领导者将检查此陈旧度量并返回StalenessExceeded错误。这使呼叫系统有机会连接到另一台主机。
将陈旧性检查推送到调用系统可能更好;让低级筏系统具有更高的可用性(以CAP术语),并让调用系统决定故障转移的过期级别。这可以通过各种方式完成。您可以将呼叫系统心跳到筏系统,但我最喜欢的是返回响应中的陈旧度量。当客户端在请求中包含其时间戳时,最后一个可以改进,筏服务器在响应中回复它,并且客户端将往返时间添加到筏式陈旧时。 (注意。Always use the nano clock in measuring time differences因为它不像系统时钟那样倒退。)
答案 2 :(得分:0)
不确定超时配置是否可以解决此问题:
2 x心跳间隔<=选举超时
这意味着在发生网络分区时,领导者A是单个领导者,并且写操作将失败,因为领导者A位于少数,并且领导者A无法从大多数节点获得回声并作为跟随者后退。
选择了领导者B之后,它可以从至少一个关注者那里赶上最新变化,然后客户可以对领导者B进行读写操作。
答案 3 :(得分:-1)
问题
对于每个读取请求,领导者必须与多数节点对话
答案:否
说明
让我们通过HashiCorp的筏实现中的代码示例来理解它。
涉及2个超时:(它们的名称不言自明,但其中包含链接以阅读详细的定义。)
示例值分别为500ms和1000ms [3]
要启动节点,必须满足以下条件:LeaderLease超时<选举超时[4,5]
一旦节点成为 Leader ,就会检查“是否在跟随者的法定人数范围内心跳” [6,7]。如果心跳停止,则可以忍受,直到LeaderLease超时[8]。如果 Leader 无法联系领导者超时的法定人数,则 Leader 节点必须成为 Follower [9]
因此,例如,在给出问题的情况下,Node-A必须先退出 Leader ,然后Node-B成为 Leader 。由于Node-A在Node-B成为Leader之前就知道自己不是Leader,因此Node-A将不满足读取或写入请求。
[1] https://github.com/hashicorp/raft/blob/9ecdba6a067b549fe5149561a054a9dd831e140e/config.go#L141 [2] https://github.com/hashicorp/raft/blob/9ecdba6a067b549fe5149561a054a9dd831e140e/config.go#L179 [3] https://github.com/hashicorp/raft/blob/9ecdba6a067b549fe5149561a054a9dd831e140e/config.go#L230 [4] https://github.com/hashicorp/raft/blob/9ecdba6a067b549fe5149561a054a9dd831e140e/config.go#L272 [5] https://github.com/hashicorp/raft/blob/9ecdba6a067b549fe5149561a054a9dd831e140e/config.go#L275 [6] https://github.com/hashicorp/raft/blob/ba082378c3436b5fc9af38c40587f2d9ee59cccf/raft.go#L456 [7] https://github.com/hashicorp/raft/blob/ba082378c3436b5fc9af38c40587f2d9ee59cccf/raft.go#L762 [8] https://github.com/hashicorp/raft/blob/ba082378c3436b5fc9af38c40587f2d9ee59cccf/raft.go#L891 [9] https://github.com/hashicorp/raft/blob/ba082378c3436b5fc9af38c40587f2d9ee59cccf/raft.go#L894