12

一般来说,如果我想确定当多个线程对 DynamoDB 中的同一个项目进行并发更新时会发生什么,我应该使用条件更新(即“乐观锁定”)。我知道。但是我想知道是否还有其他情况可以确定对同一项目的并发更新仍然存在。

例如,在 Cassandra 中,对同一项目的不同属性进行并发更新是可以的,并且两个更新最终都可以读取。在 DynamoDB 中也是如此吗?或者是否有可能只有这些更新中的一个存在?

一个非常相似的问题是,如果我同时将两个不同的值添加到同一项目中的集合或列表中,会发生什么情况。我是否保证在阅读此集合或列表时最终会看到这两个值,或者在某种 DynamoDB“冲突解决”协议期间,其中一个添加可能会掩盖另一个?

我看到我的第二个问题的一个版本过去已经在这里问过DynamoDB “设置”值 CDRT 吗?,但答案是指一个不再存在的不太清楚的常见问题解答条目。作为对我的问题的回答,我最希望看到的是官方 DynamoDB 文档,其中说明了 DynamoDB 在既不涉及“条件更新”也不涉及“事务”时如何处理并发更新,尤其是在上述两个示例中发生的情况。没有这样的官方文档,有没有人对这样的并发更新有任何实际经验?

4

2 回答 2

6

我只是有同样的问题,遇到了这个线程。鉴于没有答案,我决定自己测试一下。

据我所知,答案是只要你更新不同的属性,它最终会成功。我推送到项目的更新越多,它确实需要更长的时间,因此它们看起来是按顺序而不是并行写入的。

我还尝试并行更新单个 List 属性,这预计会失败,一旦所有查询完成,结果列表就会被破坏,并且只有一些条目被推送到它。

我进行的测试非常初级,我可能遗漏了一些东西,但我相信结论是正确的。

为了完整起见,这是我使用的脚本 nodejs。

const aws = require('aws-sdk');
const ddb = new aws.DynamoDB.DocumentClient();

const key = process.argv[2];
const num = process.argv[3];


run().then(() => {
    console.log('Done');
});

async function run() {
    const p = [];
    for (let i = 0; i < num; i++) {
        p.push(ddb.update({
            TableName: 'concurrency-test',
            Key: {x: key},
            UpdateExpression: 'SET #k = :v',
            ExpressionAttributeValues: {
                ':v': `test-${i}`
            },
            ExpressionAttributeNames: {
                '#k': `k${i}`
            }
        }).promise());
    }

    await Promise.all(p);

    const response = await ddb.get({TableName: 'concurrency-test', Key: {x: key}}).promise();
    const item = response.Item;

    console.log('keys', Object.keys(item).length);
}

像这样运行:

node index.js {key} {number}
node index.js myKey 10

时间:

  • 10 次更新:~1.5 秒
  • 100 次更新:~2 秒
  • 1000 次更新:~10-20 秒(波动很大)

值得注意的是,指标显示了很多受限制的事件,但这些是由 nodejs sdk 使用指数退避在内部处理的,因此一旦尘埃落定,一切都按预期编写。

于 2019-09-13T12:39:34.397 回答
0

您的帖子包含很多问题。

DynamoDB 的手册中有一条注释:

所有写请求都按照它们收到的顺序应用。

我假设客户端按照通过调用传递的顺序发送请求。

这应该解决是否有任何保证的问题。如果您在仅更新这些属性的多个请求中更新项目的不同属性,则它应该最终处于预期状态(不同更改的“总和”)。

另一方面,如果您更新整个对象,则最后一个将获胜。

DynamoDB@DynamoDbVersion可用于乐观锁定以管理整个对象的并发写入。

对于拍卖、并行滴答计数(例如“喜欢”)等场景,DynamoDB 提供AtomicCounters.

如果您更新列表,这取决于您是使用 DynamoDB 的列表类型 ( L),还是它只是一个属性并且客户端将列表转换为字符串 ( S)。因此,如果您读取、更改和写入属性,然后并行执行,结果将取决于最终的一致性——您将读取的可能不是最新的写入。应用于列表,并且多次,您最终会添加一些元素,而另一些则没有(或者,更好地说,添加但随后被覆盖)。

于 2021-10-12T14:58:30.050 回答