分布式最终一致性Key Value Store

Distributed eventual consistency Key Value Store

我发现很难说服自己使用 DynamoDB 等复杂设计优于简单复制策略的优势。

假设我们要在 5 个服务器上构建分布式 key/value 数据存储。 (每个服务器都有完全相同的副本)。

最终一致性系统,如DynamoDB,通常使用复杂的冲突调和、向量时间戳等方式来实现最终一致性。

但是,为什么我们不能简单地执行以下操作:

  1. 对于写入,客户端将向所有服务器发出写入命令。所以所有的服务器都会以相同的顺序执行客户端的写命令。它会在服务器提交写入之前回复客户端。
  2. 对于读取,客户端只会进行循环,一次只有一台服务器负责读取命令。 (其他服务器不会看到读取命令) 是的,客户端可能会遇到临时的陈旧数据,但最终所有副本都将具有相同的数据集,这与 DynamoDB 具有相同的语义。

这种简单的设计与复杂的 DynamoDB 相比有什么缺点?

您的策略有一些缺点,但它们的确切性质取决于您未涵盖的细节。

一个明显的例子是处理网络分段。也就是说,当您的网络的一部分与另一部分分段(断开连接)时。

在这种情况下,当您尝试将一些数据写入服务器但失败时,您有几个关于如何反应的选择。您可能只是假设它有效,然后继续,就好像一切都很好。如果您这样做,并且服务器稍后恢复联机,则读取可能 return 过时数据。

为防止这种情况,您可以将失败的写入视为真正的失败,并拒绝接受写入 until/unless 所有服务器都确认写入。不幸的是,这使得系统作为一个整体非常脆弱——事实上,比你根本不复制要脆弱得多(至少在写作方面)(因为如果 any 的服务器掉线了,你不能再写了)。它还存在另一个问题:它将写入吞吐量限制为最慢服务器的(当前)速度,因此即使它们都在工作,除非它们完全平衡(不太可能发生),否则你就是在浪费容量。

为了防止这些问题,许多系统(包括 Paxos,如果没记错的话)使用某种基于 "voting" 的系统。也就是说,您尝试写入所有服务器。当且仅当大多数服务器确认它们已收到写入时,您才认为写入完成。同样,在读取时,您尝试从所有服务器读取,并且当且仅当大多数服务器都同意该值时,您才认为该值是正确读取的。

这样一来,最多可以在任何给定时间有不到一半的服务器离线,您仍然可以读写数据。同样,如果您有几台服务器的反应比其他服务器慢一点,那不会减慢整体操作速度。

当然,您需要填写很多细节才能创建一个可用的系统——但事实上,基本概念仍然非常简单,如上所述。