我一直在测试DynamoDB作为可扩展且稳定的吞吐量数据库的潜在选择,该数据库将非常频繁地命中并且需要非常快的响应时间(<50ms)。我看到以下代码的响应很慢(本地和EC2实例):
public static void main(String[] args) {
try {
AWSCredentials credentials = new PropertiesCredentials(new File("aws_credentials.properties"));
long start = System.currentTimeMillis();
AmazonDynamoDBClient client = new AmazonDynamoDBClient(credentials);
System.out.println((System.currentTimeMillis() - start) + " (ms) to connect");
DynamoDBMapper mapper = new DynamoDBMapper(client);
start = System.currentTimeMillis();
Model model = mapper.load(Model.class, "hashkey1", "rangekey1");
System.out.println((System.currentTimeMillis() - start) + " (ms) to load Model");
} catch (Exception e) {
e.printStackTrace();
}
}
与DB的连接平均约为800 (ms)
,使用mapper
的加载需要额外200 (ms)
。根据{{3}},我们应该期望“平均服务端延迟......通常是一位数毫秒。”我不希望完整的往返HTTP请求增加那么多开销。即使在EC2实例上,这些预期数字也是如此吗?
答案 0 :(得分:4)
我认为更好的测试是避免在启动JVM和加载类时产生的初始成本/延迟。类似的东西:
public class TestDynamoDBMain {
public static void main(String[] args) {
try {
AWSCredentials credentials = new PropertiesCredentials(new File("aws_credentials.properties"));
AmazonDynamoDBClient client = new AmazonDynamoDBClient(credentials);
DynamoDBMapper mapper = new DynamoDBMapper(client);
// Warm up
for (int i=0; i < 10; i++) {
testrun(mapper, false);
}
// Time it
for (int i=0; i < 10; i++) {
testrun(mapper, true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void testrun(DynamoDBMapper mapper, boolean timed) {
long start = System.nanoTime();
Model model = mapper.load(Model.class, "hashkey1", "rangekey1");
if (timed)
System.out.println(
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)
+ " (ms) to load Model");
}
}
此外,您可以考虑启用AWS SDK for Java的默认指标,以查看Amazon CloudWatch中的细粒度时间分配。有关更多详细信息,请参阅:
http://java.awsblog.com/post/Tx1O0S3I51OTZWT/Taste-of-JMX-Using-the-AWS-SDK-for-Java
希望这有帮助。
答案 1 :(得分:3)
Dynamo DB位于特定区域(它们尚不支持跨区域复制)。创建表时由您选择。除非您从同一区域调用API,否则它必然会很慢。
您似乎正在尝试从开发桌面调用Dynamo。您可以从“相同区域”中启动的EC2实例重新执行相同的测试。这将大大加快响应速度。这是一个更现实的测试,因为在部署生产系统时,它将与Dynamo位于同一区域。
同样,如果您真的需要非常快速的响应,请考虑在代码和Dynamo之间使用ElastiCache。在每次读取时,在返回结果之前存储在缓存中。下一次读取应该从缓存中读取(比如10分钟的到期时间)。对于“阅读量大”的应用程序,这是建议的路线。我已经看到使用这种方法可以获得更好的响应。