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