amazon-dynamodb - 仅在 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')
解决方案
实际上,Dynamo 中一致性的一个限制是您需要准确地告诉 Dynamo 它应该对哪些项目 (PK/SK) 进行操作。正如您所提到的,这在 SQL 中相对微不足道,但与 Dynamo 一样,另一方面是也相对不可能使 SQL 的方式实现网络规模...... :)
解决此问题的一种方法是在您的 tx 中添加一个额外的“跟踪”项目,包括 PKX
和 SKcurrent_pending
或类似的东西。在您的 TX 中,添加此项目,并确认它不存在。这两个跟踪项本身是相互独立的,但它们不能都成功创建,因为其中只有一个还没有current_pending
SK。然后,当一个项目不再待处理时,也删除current_pending
同一个 TX 中的项目以释放“锁定”。
Dynamo 中的很多事务和一致性问题都是通过添加更多项来解决的!
推荐阅读
- amazon-web-services - 如果响应正文不是字符串化,aws api 网关返回“内部服务器错误”
- javascript - 同步 SQL 查询后 res.send 将不起作用
- python - 将文本文件转换为字典
- html - 侧边栏滚动不起作用。只有页面滚动有效
- python - “for i in range (...)”之前的内容
- angular - 为什么在角度区域之外运行仍然会触发变化
- php - 如何将 daterangepicker 的值传递到另一个 php 页面
- julia - Julia 包“没有已知版本!” 尝试添加包时
- c# - Blazor - Windows 身份验证
- java - 检测用户何时在特定位置