首页 > 解决方案 > 仅在 PK 上的 DynamoDB 更新项目条件

问题描述

我有一些 DynamoDB 数据,如下所示:

PK:              SK:
subscriptionId | changeId       | status     | scheduled_for |
--------------------------------------------------------------
A              | 19695a80-e3... | DONE       | 2009-01-01    |
A              | 3327f283-a1... | DONE       | 2012-11-13    |
X              | aebb5fe4-78... | DONE       | 2019-06-24    |
X              | 8982f726-69... | PENDING    | 2022-01-01    |

如果提出新的更改请求,我目前取消旧更改并按如下方式等待新更改:

PK:              SK:
subscriptionId | changeId       | status     | scheduled_for |
--------------------------------------------------------------
A              | 19695a80-e3... | DONE       | 2009-01-01    |
A              | 3327f283-a1... | DONE       | 2012-11-13    |
X              | aebb5fe4-78... | DONE       | 2019-06-24    |
X              | 8982f726-69... | CANCELLED  | 2022-01-01    |
X              | 1f3380aa-f2... | PENDING    | 2022-02-01    |

同一订阅的两个请求同时进入的可能性很小,因此我认为保证只有一个“待处理”记录的最佳方法是在事务中使用 ConditionCheck 并避免任何往返竞争条件- 例如

// Only insert if there is no PENDING item for the subscriptionId
writeItems := []*dynamodb.TransactWriteItem{
    {
        ConditionCheck: &dynamodb.ConditionCheck{
            TableName:           aws.String("subscription_changes"),
            ConditionExpression: aws.String("attribute_not_exists(changeId)"),
            Key: map[string]*dynamodb.AttributeValue{
                "status":         {S: aws.String("PENDING")},
                "subscriptionId": {S: aws.String(subscriptionId)},
            },
        },
    },
    {
        Put: &dynamodb.Put{
            TableName: aws.String("subscription_changes"),
            Item:      attributesMap,
        },
    },
}

...但是,DynamoDB 希望我在我的条件中包含排序键(changeId),如果不查询数据我无法知道(因此打开了两个线程“获胜”的竞争条件的可能性,我们表中有两个 PENDING 项)。

有没有办法做到这一点?

在 SQL 中,这将类似于:

INSERT subscription_items 
      (subscriptionId, changeId, status, ...)

SELECT 'X', '1f3380aa-f2...', 'PENDING', ...

WHERE NOT EXISTS (SELECT 1 
                  FROM   subscription_items
                  WHERE subscriptionId = ‘X’ AND status = 'PENDING')

标签: amazon-dynamodb

解决方案


实际上,Dynamo 中一致性的一个限制是您需要准确地告诉 Dynamo 它应该对哪些项目 (PK/SK) 进行操作。正如您所提到的,这在 SQL 中相对微不足道,但与 Dynamo 一样,另一方面是也相对不可能使 SQL 的方式实现网络规模...... :)

解决此问题的一种方法是在您的 tx 中添加一个额外的“跟踪”项目,包括 PKX和 SKcurrent_pending或类似的东西。在您的 TX 中,添加此项目,并确认它不存在。这两个跟踪项本身是相互独立的,但它们不能都成功创建,因为其中只有一个还没有current_pendingSK。然后,当一个项目不再待处理时,也删除current_pending同一个 TX 中的项目以释放​​“锁定”。

Dynamo 中的很多事务和一致性问题都是通过添加更多项来解决的!


推荐阅读