繁体   English   中英

DynamoDB 更新是否高度一致?

[英]Are DynamoDB Updates strongly consistent?

DynamoDB 快速且可扩展的全部原因是基于它的最终一致性这一事实。 但与此同时,它为getbatchGetquery等操作提供了ConsistentRead选项,可帮助您确保正在读取的数据是最新的。

我的问题是关于update操作。 首先,它没有ConsistentRead选项(一个原因是, update不是读取。),但与此同时,您可以使用ConditionExpression以原子方式更新记录,如下所示:

await docClient.update({
    TableName: 'SomeTable',
    Key: {id},
    UpdateExpression: "set #status = :new_status",
    ConditionExpression: '#status = :old_status',
    ExpressionAttributeNames: {
        "#status": "status",
    },
    ExpressionAttributeValues: {
        ":old_status": "available",
        ":new_status": "done",
    },
}).promise()

这将确保在更新时,旧值available ,如果不可用,操作将失败并抛出异常。 所以,从某种意义上说,你可以说update是强一致的。

但我的问题是关于您需要确保记录存在的场景。 假设您有一个 function 插入一条记录。 另一个更新同一条记录(给定它的id )。 我担心的是,如果在执行update操作时,由于 DynamoDB 的最终一致性,没有匹配的记录并且更新失败怎么办。 如前所述, update操作不带有ConsistentRead选项以使其具有强一致性。

这是一个合理的担忧吗? 有什么我可以做的吗?

没有强烈一致的更新。 强一致性适用于读取,其中基本上在写入后立即查看的数据对于实体的所有观察者来说都是一致的。

当您的应用程序将数据写入 DynamoDB 表并收到 HTTP 200 响应 (OK) 时,写入已发生(在至少一个存储位置)并且是持久的。 数据最终在所有存储位置保持一致,通常在一秒或更短的时间内。 然后,您可以选择以最终一致性或强一致性方式读取此数据。

应使用乐观并发处理对同一项目的并发写入,您可以使用 DynamoDB 事务库(适用于 Java 的 AWS SDK 中提供)进行条件写入

如果您需要以原子方式更新多个项目,您可以使用 DynamoDB 事务。

DynamoDB 事务为开发人员提供跨单个 AWS 账户和区域内的一个或多个表的原子性、一致性、隔离性和持久性 (ACID)。 在构建需要对多个项目进行协调插入、删除或更新作为单个逻辑业务操作的一部分的应用程序时,您可以使用事务。

https://aws.amazon.com/blogs/aws/new-amazon-dynamodb-transactions/

或者,您的用例可能会受益于DynamoDB 全局表,该表在并发写入之间使用“最后写入者获胜”协调。

这个问题过去在这里被问过很多次,例如参见

dynamodb 更新表达式是否具有强一致性?

DynamoDB 条件写入是否具有强一致性?

上面接受的答案或多或少表明,在作为写入的一部分发生的读取中,所有赌注都已关闭,并且您不能相信它们是一致的 - 因此您需要使用新的“DynamoDB 事务”功能。 但我认为那个答案的结论是错误的。 当您有一个事务需要隔离对几个不同项目的写入并安全地支持失败的非幂等写入时,就需要新的“DynamoDB 事务”。 但是在UpdateItem支持的单项更新中,我相信涉及的先读后写实际上是强一致的:

不幸的是,DynamoDB 的文档对此并不完全清楚,但这里有一些来自 DynamoDB 文档的证据来支持我的信念:

  1. 有几个原因导致UpdateItem可能需要读取项目的旧值(所谓的先读后写)——问题是这些读取的一致性。 读取的原因之一是UpdateExpression (例如,更新可以增加属性),另一个是ConditionExpression (更新可以以属性的旧值为条件),第三种情况是ReturnValues用户要求获取项目的旧值。 尽管UpdateItem 文档没有明确说明前两种情况下的一致性,但对于第三种情况下的一致性却非常明确: “返回的值是强一致的”。 . 我看不出为什么在这种情况下先读后写是强一致的,而在其他情况下则不是,所以我相信它在所有三种情况下都是强一致的。
  2. 来自 DynamoDB 的 DynamoDB 内部结构的几个演示解释了它在内部是如何工作的:它为每条数据保留三个副本,并且在任何时候三个副本中的一个被认为是“领导者”; 始终首先将 go 写入领导者,并在领导者和第二个副本成功时成功,最终一致性随机将 go 读取到三个副本之一(因此可能从一个尚未收到写入的副本读取)但强烈-consistent 始终读取 go 给领导者。 这意味着强一致性读取和写入 go 到同一个副本(领导者),并具有相同的一致性保证。 此外,领导者线性化了对该项目的写入(即,按某种顺序进行,而不是同时进行),因此一次写入的先读后写可以看到之前写入同一项目时写入的所有内容。

以上所有答案都不正确。 没有写入强一致性。

UpdateItem 将在复制组的领导节点被确认时返回,一旦对等点的法定人数将日志记录保存到他们的本地预写日志中。 这意味着只有预写日志被复制到日志节点,而不是实际的存储节点。 因此 UpdateItem 不保证复制组中的所有存储节点都能成功写入。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM