DynamoDB - 写入操作非常慢
DynamoDB - very slow write operations
我在 AWS 云中有一个 DynamoDB 运行,我在定期(计划)基础上用数据填充它。基本上每小时一次,我收到一个需要处理的文件,结果必须保存在数据库中。
我正在使用以下 class 来处理数据库连接并执行批量写入:
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.");
}
}
问题是写入速度非常慢。我阅读了文档并增加了吞吐量(因此它现在应该支持超过 300000 writes/hour)但是处理一个包含大约 1 个列表需要超过 15 分钟。 8000 条记录。
我读到一个批处理操作的最佳写入数是 25,一条记录的大小低于 1kb。我在我的本地机器(我知道由于流量开销,它会变慢)和 AWS worker 环境中都测试了它,但结果都很慢。有什么方法可以优化这个过程吗?
首先,为了避免在多个线程中有多个 DynamoDBMapper/client 实例,请将 Mapper 和 AmazonDynamoDB 客户端设为静态。其次,您应该使用 Guava RateLimiter 或类似工具进行自我节流。将速率设置为等于您在 table 上配置的每秒写入次数,并在每次 batchWrite 调用之前获得 25 个许可,只要您的项目小于 1KB。第三,您可以 运行 mapper.batchWrite 并行调用。每小时 300000 次写入大约是每秒 83 次写入。这意味着你的 table 可能有 1 个分区,只要你的 table 中存储的数据量小于 10GB(我假设这是真的)。第四,可以减少客户端配置中的dynamodb.timeout。这可能会有所帮助,因为 BatchWrite 操作与批处理中最潜在的单个 PutRequest 一样潜在。您也可以尝试减少或关闭 SDK 重试。
请注意,分区支持的每秒最大写入次数为 1000。您过去可能预配太多,导致 table 拆分 IOPS。如果您有一个 Hash+Range 模式,并且您将许多项目写入相同的哈希键但不同的范围键,那么所有这些写入都将写入同一个分区。因此,即使 table 上所有写入容量的总和可能是每秒 83 次写入,您也可能遇到这样的情况:您有很多分区并且分区级别的写入配置不足以支持您的负载.
在这种情况下,有两种可能的方法。您可以开始对您的散列键进行分区,并使用 key1、key2、key3 等作为相同逻辑 "key" 的散列键,并在您的项目的范围键上使用散列和模除法来决定哪个散列键分区项目应该被写入。第二个也是更好的选择是评估您的架构以确保您的写入在哈希范围键 space.
之间均匀分布
我在 AWS 云中有一个 DynamoDB 运行,我在定期(计划)基础上用数据填充它。基本上每小时一次,我收到一个需要处理的文件,结果必须保存在数据库中。
我正在使用以下 class 来处理数据库连接并执行批量写入:
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.");
}
}
问题是写入速度非常慢。我阅读了文档并增加了吞吐量(因此它现在应该支持超过 300000 writes/hour)但是处理一个包含大约 1 个列表需要超过 15 分钟。 8000 条记录。
我读到一个批处理操作的最佳写入数是 25,一条记录的大小低于 1kb。我在我的本地机器(我知道由于流量开销,它会变慢)和 AWS worker 环境中都测试了它,但结果都很慢。有什么方法可以优化这个过程吗?
首先,为了避免在多个线程中有多个 DynamoDBMapper/client 实例,请将 Mapper 和 AmazonDynamoDB 客户端设为静态。其次,您应该使用 Guava RateLimiter 或类似工具进行自我节流。将速率设置为等于您在 table 上配置的每秒写入次数,并在每次 batchWrite 调用之前获得 25 个许可,只要您的项目小于 1KB。第三,您可以 运行 mapper.batchWrite 并行调用。每小时 300000 次写入大约是每秒 83 次写入。这意味着你的 table 可能有 1 个分区,只要你的 table 中存储的数据量小于 10GB(我假设这是真的)。第四,可以减少客户端配置中的dynamodb.timeout。这可能会有所帮助,因为 BatchWrite 操作与批处理中最潜在的单个 PutRequest 一样潜在。您也可以尝试减少或关闭 SDK 重试。
请注意,分区支持的每秒最大写入次数为 1000。您过去可能预配太多,导致 table 拆分 IOPS。如果您有一个 Hash+Range 模式,并且您将许多项目写入相同的哈希键但不同的范围键,那么所有这些写入都将写入同一个分区。因此,即使 table 上所有写入容量的总和可能是每秒 83 次写入,您也可能遇到这样的情况:您有很多分区并且分区级别的写入配置不足以支持您的负载.
在这种情况下,有两种可能的方法。您可以开始对您的散列键进行分区,并使用 key1、key2、key3 等作为相同逻辑 "key" 的散列键,并在您的项目的范围键上使用散列和模除法来决定哪个散列键分区项目应该被写入。第二个也是更好的选择是评估您的架构以确保您的写入在哈希范围键 space.
之间均匀分布