2017-01-23 174 views
1

我们在过去的几周内在我们的项目中开始使用DynamoDB,既作为缓存,也作为系统中发生的事件列表(请让我们不要理解为什么有更好的替代方案来实现这一点,我认为在DynamoDB被选中之前我自己没有结果)。处理DynamoDB的最佳做法batchGetItem的未处理键

看来由于预配置的吞吐量限制,我期望在我的代码中实现一种方法,在超出限制时重试未处理的项目。它是有道理的,但它也提出了有关批量操作或查询的问题,这些问题我自己似乎无法回答。

我认为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调用的输出。我不能在这里做指数重试,否则用户可能会等待很长时间。另一方面,我也不能不显示我要求的钥匙的所有结果。

有没有人有任何建议,正确的方式(我会解决一个体面的方式)处理这个? 我是否以错误的方式接近问题?

我正在使用亚马逊JavaSDK顺便说一句。

回答

1

对于我所问的问题(我真的不认为有一个,请随时纠正我)并不是真正的答案,但我重新以我考虑问题的方式工作,而且它实际上感觉像一个设计良好的解决方案,而不是hacky。当你考虑这个问题时很明显,但是我几天完全忽略了它,所以我认为这是值得分享的。

我最终将重试逻辑放在GetBatchItem的客户端上,这样我就可以显示可以直接检索的结果。我的后端代码100%不含任何未处理项目的重试逻辑。

我的后端端点按照您的预期返回项目列表和未处理的键列表。

{ 
    "items": [{ 
    "myPartitionKey": "whatever", 
    "mySortKey": "whocares", 
    "item": "myitem" 
    }, (...)], 
    "unprocessedKeys": [{ 
    "pKey": "unprocessed1" 
    "sKey": "blah" 
    }, (...)] 
} 

然后它给我的ReactJs客户端更新部分基于数据成功接收的UI,并只与丢失的钥匙再次调用同样的服务,与某种指数退避的。