对于使用适用于Apache Cassandra的DataStax Java驱动程序的多线程,高吞吐量低延迟Java客户端的最佳设置,我表示感谢。我不赞赏“滚动你自己”的基准测试,但是这项任务也是为了实现高TPS的实际应用的概念验证。
客户端:Java 8客户端,可配置数量的多线程执行程序线程(由lmax disruptor推动), cassandra-driver-core-3.0.0.jar ,运行在Redhat 6.3,24核心机器上,dl360s 服务器端:3个节点Cassandra集群( apache-cassandra-2.2.4 ,在Redhat 6上使用Java 8),复制因子= 3,在Redhat 6.3上运行,24核机器dl360s
使用cl = LOCAL_QUORUM测试从相对简单的模式开始,每秒测试 3.5K INSERTS和6.5K READS ,延迟分别大约为6和2毫秒,CPU使用率大约为20整个盒子里的百分比。
然而,我无法解决的问题是 - 当我创建我的加载客户端应用程序的多个单独实例时,我可以实现跨实例的显着更高的TPS总和,以及比我在单个内容中实现的更高的CPU使用率JVM 即可。这表明我的Java客户端应用程序既不是IO也不是CPU绑定,服务器端的Cassandra集群也不是瓶颈。同样,当我发出Cassandra调用时,我获得了更高的TPS,从而让我相信应用程序没有遭受任何争用。
所以我的问题是:这是一个常见的问题 - 使用DataStax Java Driver for Apache Cassandra的单个Java客户端在某种程度上限制了它的吞吐量吗?如果没有,任何人都可以指出我正确的方向进行调查。
我测试了多个序列(READ和WRITE),还有execute和executeAsync,并且可变数量的并发线程。正如您所期望的那样,我使用executeAsync看到更高的数字,但在我的应用程序中仍然存在相同的限制。
我已经使用多个连接池设置进行了测试,并尝试为每个客户端应用程序创建/构建1个群集实例,并为每个应用程序创建/构建多个群集实例,并尝试改变CoreConnections,maxRequestsPerConnection和newConnectionThreshold值,但迄今为止没有成功。
我当前最好的结果是有50个执行程序线程,5个实例; MaxRequestsPerConnection(L)= 1024; ; NewConnectionThreshold(L)= 800; CoreConnectionsPerHost(L)= 20
这只产生~4 / 4 TPS BUT只使用了18%的CPU,当我启动一个单独的应用程序实例时,我使用30%的CPU实现了7.5K TPS,但是我无法在保存JVM中实现这个7.5K < / p>
代码:创建群集
LoadBalancingPolicy tokenAwarePolicy =
new TokenAwarePolicy(new RoundRobinPolicy());
Cluster cluster = Cluster.builder()
.addContactPoints(node)
.withLoadBalancingPolicy(tokenAwarePolicy)
.withPoolingOptions(new PoolingOptions()) // Have tried various options here
.build();
代码:准备声明(一次)
String insertSqlString = "INSERT INTO " + keySpaceName + ".test_three ("
+ "user_id, field_a, field_b, field_c, field_d) values "
+ "( ?, ?, ?, ?);";
statementInsertDataTablePS = session.prepare(insertSqlString);
statementInsertDataTablePS.setConsistencyLevel(configuredConsistencyLevel); //2
代码:执行
BoundStatement boundStatement = new BoundStatement(statementInsertDataTablePS);
session.executeAsync(boundStatement.bind(
sequence, // userID
sequence + "value_for_field_a",
sequence + "value_for_field_b",
sequence + "value_for_field_c",
sequence + "value_for_field_d") );