DynamoDB - 非常慢的写入操作

Sma*_*ajl 3 java amazon-web-services amazon-dynamodb

我有一个在 AWS 云中运行的 DynamoDB,我正在用常规(预定)基础上的数据填充它。基本上,每小时一次,我会收到一个需要处理的文件,并且必须将结果保存在数据库中。

我正在使用以下类来处理数据库连接并执行批量写入:

public class DynamoDBService {

  private final AmazonDynamoDB amazonDynamoDB = new AmazonDynamoDBClient();
  private final DynamoDBMapper mapper = new DynamoDBMapper(amazonDynamoDB);

  @Value("${aws_region}")
  private String region;

  @PostConstruct
  public void init() {
    log.info("Region: {}", region);
    amazonDynamoDB.setRegion(RegionUtils.getRegion(region));
  }

  /**
   * 
   * @param records
   */
  public void saveRecord(final Collection<Record> records) {
    log.info("Saving records...");

    // create table if necessary here

    List<Record> recordsToSave = new ArrayList<Record>(100);

    for (Record record : records) {

      recordsToSave.add(record);

    }

    // save the records
    List<FailedBatch> failedBatch = mapper.batchWrite(recordsToSave, new ArrayList<Record>());
    // process failed writes here

    log.info("All records have been saved.");
  }
}
Run Code Online (Sandbox Code Playgroud)

问题是写入速度非常慢。我阅读了文档并增加了吞吐量(所以它现在应该支持超过 300000 次写入/小时)但是处理一个包含大约 8000 条记录。

我读到一个批处理操作中的最佳写入次数是 25,并且一条记录的大小低于 1kb。我在我的本地机器上(我知道由于流量开销会变慢)和 AWS 工作环境中测试它,但结果都很慢。有什么方法可以优化这个过程吗?

Ale*_*kis 7

首先,为了让您在多个线程中没有多个 DynamoDBMapper/client 实例,将 Mapper 和 AmazonDynamoDB 客户端都设为静态。其次,您应该使用 Guava RateLimiter 或类似工具进行自我调节。将速率设置为等于您在表上配置的每秒写入次数,并在每次 batchWrite 调用之前获取 25 个许可,只要您的项目小于 1KB。第三,您可以并行运行 mapper.batchWrite 调用。每小时 300000 次写入大约是每秒 83 次写入。这意味着您的表可能有 1 个分区,只要您表中存储的数据量小于 10GB(我假设这是真的)。第四,可以减少客户端配置中的dynamodb.timeout。这可能会有所帮助,因为 BatchWrite 操作与 Batch 中最潜在的单个 PutRequest 一样潜在。

请注意,分区上支持的每秒最大写入数为 1000。您可能在过去进行了过多的升级,导致您的表因 IOPS 而被拆分。如果您有一个 Hash+Range 架构,并且您将许多项目写入相同的散列键但不同的范围键,那么所有这些写入都将写入同一个分区。因此,即使表上所有写入容量的总和可能是每秒 83 次写入,您也可能会遇到这样的情况:您有许多分区,而分区级别的写入配置不足以支持您的负载。

在这种情况下,有两种方法是可能的。您可以开始对散列键进行分区,并使用 key1、key2、key3 等作为相同逻辑“键”的散列键,并对项目的范围键使用散列和模除法来决定项目应该使用哪个散列键分区被写入。第二个也是更好的选择是评估您的架构以确保您的写入在散列范围键空间中均匀分布。