亚马逊 - DynamoDB 强一致性读取,它们是最新的吗?如何实现?

48
在尝试将Dynamodb用于我的一个项目时,我对dynamodb的强一致性模型存在疑问。从常见问题解答中,强一致性读取不仅支持最终一致性,而且还可以根据应用程序或应用程序的某个元素需要,请求强一致性读取。强一致性读取返回反映在读取之前成功响应的所有写入的结果。从上面的定义中,我得到的是强一致性读取将返回最新的写入值。
举个例子:假设客户端1发出写入命令来更新密钥K1的值从V0到V1。几毫秒后,客户端2发出了对密钥K1的读取命令,在强一致性的情况下,始终会返回V1,但是在最终一致性的情况下,可能会返回V1或V0。我的理解正确吗?
如果是这样,如果写操作返回成功但未将数据更新到所有副本,并且我们发出强一致性读取,如何确保在这种情况下返回最新的写入值?
以下链接AWS DynamoDB读写一致性-理论上如何工作?试图解释其架构,但不知道这是否是实际情况?在阅读此链接后,接下来我想到的问题是:DynamoDb基于单主多从架构吗,在该架构中,写入和强一致性读取通过主副本进行,而正常读取则通过其他方式进行。
4个回答

44
简短回答:在强一致模式下成功写入需要在可能包含记录的大多数服务器上写入,因此任何未来的一致性读取都将看到相同的数据,因为一致性读取必须读取可能包含所需记录的大多数服务器。如果您不执行强一致性读取,则系统将向随机服务器请求记录,可能导致数据不是最新的。
假设有三个服务器:服务器1、服务器2和服务器3。要写入强一致记录,您至少选择两个服务器并写入数据。让我们选择1和2。
现在您想要一致地读取数据。选择大多数服务器。假设我们选择了2和3。
服务器2具有新数据,这就是系统返回的内容。
最终一致性读取可以来自服务器1、2或3。这意味着如果随机选择服务器3,则您的新写入尚未出现,直到复制发生为止。
如果单个服务器失败,您的数据仍然安全,但如果三个服务器中有两个失败,则可能会丢失您的新写入,直到离线服务器恢复为止。
更多解释: DynamoDB (假设它类似于亚马逊发布的Dynamo论文中描述的数据库)使用环形拓扑结构,其中数据分布到许多服务器。强一致性得到保证,因为您可以直接查询所有相关服务器并从中获取当前数据。环中没有主节点,也没有从节点。给定记录将映射到环中若干个相同的主机,并且所有这些服务器都将包含该记录。没有可能滞后的从节点,也没有可能失败的主节点。
随意阅读任何有关此主题的论文。还有一个名为Apache Cassandra的类似数据库可用,它也使用环形复制。

http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf


11
您所描述的架构是 Dynamo 论文中的架构,而不是 DynamoDB 的。尽管它们有相同的名称,但不清楚是否使用了相同的架构。 - Will Holley
同一个客户端(例如C1)在发出写操作后立即进行读取,是否可能遇到读取不一致的情况? - user2098324
1
我认为DynamoDb使用的是单主架构,这与Dynamo非常不同。 - suitianshi

17

您可以在此处找到问题的答案:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/APISummary.html

当您发出强一致性读取请求时,Amazon DynamoDB将返回一个响应,其中包含最新的数据,反映了所有之前相关写操作的更新,这些操作已经得到了Amazon DynamoDB成功响应。

在您的示例中,如果updateItem请求成功更新了从v0v1的值,则随后的强一致性读取请求将返回v1

希望这能帮到您。


2
感谢您的回答,Swami。我的理解有些相同,但想确认一下。对于它是如何实现的,您有任何架构方面的了解吗? - User23890
@User23890 基本概念是,当您写入一个键时,它将存储在多个副本中。一旦在大多数副本上成功写入,则调用返回成功,但某些副本可能会落后直到它们赶上为止。如果您读取该键,则有可能在一段时间内获得过时的值,因此出现了“最终一致性”。您可以通过从所有副本中读取值并选择存在于大多数节点上的值来立即获得一致性读取。 - Kevan Ahlquist
嗨Kevan,你的评论:“您可以通过从所有副本中读取值并选择在大多数节点上存在的值来立即获得一致的读取。” - 因此想象一下3个服务器s1,s2,s3 - 并且k1 = v1存在于它们所有的服务器上,然后(1)s1关闭,(2)客户端发出写入以更新k1 = v2,该写入成功地在s2和s3上执行,然后(3)s2关闭并且s1重新启动,然后客户端从s1读取:k1 = v1,s2:k1 = v2 - bodrin
3
这并没有回答问题。OP已经解释了他的理解。请进一步改进。 - sumitya

12

是的,强一致性读取是最新的,但仅当您从基础表或本地二级索引中进行读取时。强一致性读取始终来自数据所在分区的领导节点。要更好地理解这一点,您必须了解 DynamoDB 中的写入方式。当您写入项目时,为了使客户端获得 200 OK 确认,写入必须发送到领导节点和该分区的一个追随者(副本)。如果没有发生这种情况,您将无法收到 200 OK 的返回。因此,如果您请求强一致性读取,则该读取来自该分区的领导者。在这种情况下,很可能还写入了该分区的第三个节点,但对于向客户端返回确认是不必要的。

如果您请求最终一致性读取(默认值),则该读取可以来自该分区的任何一个节点。您有 2/3 的机会获取该项目的最新版本并且假定尚未在第三个节点上进行写入,而这可能已经发生。

如果您从全局二级索引(GSI)中进行读取,则始终是最终一致性读取,截至本文撰写时。

如需更多信息,我建议查看Jaso Sorenson在2018年re:Invent的演讲

免责声明:我曾是DynamoDB团队的成员。


5

免责声明:以下内容无法通过公共DynamoDB文档进行验证,但它们可能非常接近真相

从理论上讲,DynamoDB利用仲裁,其中V是副本节点的总数,Vr是读操作请求的副本节点数量,而Vw是每个写入操作执行的副本节点数量。读取仲裁(Vr)可以用来确保客户端获取最新值,而写入仲裁(Vw)可以用来确保写入不会创建冲突。

基于DynamoDB中不存在写入冲突的事实(因为这些必须从客户端进行协调,因此在API中暴露),我们得出结论,DynamoDB正在使用符合第二定律的Vw(Vw > V/2),可能只是V/2+1以减少写入延迟。

关于读取仲裁,DynamoDB提供2种不同的读取方式。强一致性读取使用符合第一定律(Vr + Vw > V)的读取仲裁,如果我们假设写入时V/2+1,则可能只使用V/2。但是,最终一致性读取只能使用单个随机副本Vr = 1,因此速度更快,但不能保证一致性。
注意:写入仲裁可能不符合第二定律(Vw > V/2),但这意味着DynamoDB会自动解决此类冲突(例如通过基于本地时间选择最新的冲突)而无需客户端协调。但我认为这种情况真的很少见,因为DynamoDB文档中没有相关参考。即使在这种情况下,其余推理也是相同的。

随着最新的DynamoDB论文发布(链接在此处:https://www.usenix.org/system/files/atc22-elhemali.pdf),现在有了一个(在某种程度上)明确的答案。每个分区由一组形成共识/复制组的副本托管。其中一个副本被选为该组的领导者,负责服务于所有写请求和强一致性读请求。组中的任何副本都可以提供最终一致性读取。 - Dimos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接