给定两个将军问题,如何实现强一致性



许多分布式系统(例如数据库)表示它们可以提供强一致性。例如,假设数据的副本N,要求W节点确认写入,R副本响应读取,Cassandra 文档说只要R + W > N,你就会获得强一致性。直觉上,这是有道理的。但后来我开始在个人消息级别上考虑这个问题,我实际上无法理解它是如何实现的。

具体来说,假设我有一个复制因子为 3 的 Cassandra 集群。为简单起见,让我们假设只有一个数据分区,因此系统中正好有 3 个节点,ABC个节点。客户端尝试写入一些数据,x = 11,写入一致性为W = 3,也就是说,仅当所有副本都确认写入时,写入才被视为完成。因此,客户端将写入请求发送给A然后将其转发给BC。让我们假设B确认写入,但C没有。然后写入应失败。然后,另一个客户端与R = 1一起读取,并碰巧与B交谈。R + W = 1 + 3 = 4 > 3这应该是一个强一致性的阅读。但是,B已经确认了写入,因此如果被询问,B至少会在一段时间内返回x = 11(它可能只是一个窗口,因为A可能会告诉B"没关系,写入失败")。如果客户端从不重试写入,我们现在向客户端提供了完全不正确的数据,并且似乎我们无法考虑这种强一致性。

我们可以开始考虑解决这个问题的方案。例如,也许协议是每个节点AC消息,但在A再次联系它们并告诉它们提交(即两阶段提交)之前不会返回它。但是我们再次遇到麻烦,因为现在我们可以B并且最初CACK,所以A告诉他们提交,但C未能收到该消息。因此,即使写入似乎已成功,从C读取也无法返回x = 11。尝试通过额外的消息传递轮次来解决此问题(例如,每个节点都必须确认提交阶段)也不可避免地会遇到问题,正如两个一般问题所证明的那样。

我在这里的推理显然有问题;如果使用得当,Cassandra确实提供了很强的一致性。我的问题是,在节点到节点协议级别,他们是如何做到的?

我认为这里的答案是这里的"强一致性"类似于未提交的读取,这意味着脏读,就像我最初的例子一样,实际上是允许的,并且确实发生了。事实上,我在Cassandra文档中发现了这一点:

如果其中一个节点上的写入失败,但在另一个节点上成功,Cassandra 将报告在该节点上复制写入失败。但是,在其他节点上成功的复制写入不会自动回滚。

最新更新