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