DynamoDB仅在PK上更新项条件



我有一些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    |

有一个(很小的)可能性,两个请求相同的订阅同时进入,所以我认为保证只有一个'PENDING'记录的最好方法是在事务中使用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希望我在我的条件中包含Sort Key (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的方式做到web规模…:)

解决这个问题的一种方法是添加额外的"tracking"项目在你的tx,与PKX和SKcurrent_pending或类似的东西。在您的TX中,添加此项目,并验证它是否已经存在。这两个跟踪项目本身是相互独立的,但它们不能都成功地创建,因为只有其中一个将不会已经有current_pendingSK到位。然后,当一个项目不再挂起时,也删除同一TX中的current_pending项目以释放"锁"。

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

最新更新