我们在过去几周内开始在我们的项目中使用DynamoDB,既作为缓存,也作为系统中发生的事件列表(请不要理解为什么有更好的替代方案来实现这一点,在选择DynamoDB之前,我自己认为自己没有结果)。
似乎由于预配置的吞吐量限制,我希望在我的代码中实现一种在超出限制时重试未处理项目的方法。这是有道理的,但它也引发了有关批量操作或查询的问题,而我似乎无法自己回答。
我认为BatchPutItem很容易实现。如果我得到未处理的项目,我只是使用指数重试,这些项目最终会被持久化。我正在做这样的事情:
(...)
BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(new TableWriteItems(tableName).withItemsToPut(items));
processUnprocessed(outcome, 0);
(...)
和
private void processUnprocessed(BatchWriteItemOutcome outcome, int retryNumber) {
if (MapUtils.isEmpty(outcome.getUnprocessedItems())) {
return;
}
if (retryNumber > maxRetries) {
log.error(Joiner.on(" ").join("Unable to process", outcome.getUnprocessedItems().size(), "items after", retryNumber, "tries"));
return;
}
long retryTime = (long)Math.pow(retryFactor, retryNumber);
log.info("Exceeded provisioning throughput. Retrying in " + retryTime);
try {
Thread.sleep(retryTime);
} catch (InterruptedException e) {
log.error(e.getMessage());
}
processUnprocessed(dynamoDB.batchWriteItemUnprocessed(outcome.getUnprocessedItems()), ++retryNumber);
}
由于异步后台任务正在填充数据库,因此可以正常工作。
对于查询或BatchGetItem,它并不那么简单。最终用户正在等待DynamoDB调用的输出。我不能在这里进行指数重试,否则用户可能会等待很长时间。另一方面,我也无法显示我要求的钥匙的所有结果。
有没有人有任何关于正确处理这个问题的正确方法的建议(我会以体面的方式解决)吗? 我是以错误的方式解决问题吗?
我正在使用Amazon JavaSDK btw。
答案 0 :(得分:1)
不是我问过的问题的答案(而且我真的不认为有一个,请随意纠正我),但我按照我正在思考问题的方式重新工作,它实际上感觉就像一个精心设计的解决方案,而不是hacky。当你想到它时很明显,但我已经完全错过了几天,所以我觉得值得分享。
我最终只在GetBatchItem的客户端上放置了重试逻辑,这样我就可以显示可以立即检索的结果。我的后端代码100%没有任何未处理项目的重试逻辑。
我的后端端点返回一个项目列表和一个未处理的Keeys列表,正如您所期望的那样。
{
"items": [{
"myPartitionKey": "whatever",
"mySortKey": "whocares",
"item": "myitem"
}, (...)],
"unprocessedKeys": [{
"pKey": "unprocessed1"
"sKey": "blah"
}, (...)]
}
然后由我的ReactJs客户端根据成功收到的数据部分更新UI,并仅使用缺少的密钥再次调用相同的服务,并进行某种指数退避。