Java 异步写入在Cassandra中似乎被破坏了
在向12节点cassandra(2.1.2)集群写入900万行的批时,我遇到了spark cassandra连接器(1.0.4,1.1.0)的问题。我写的是一致的,读的是一致的,但每次读的行数都不同于900万行(8.865.753、8.753.213等等) 我检查了连接器的代码,没有发现任何问题。然后,我决定独立于spark和连接器编写自己的应用程序来研究这个问题(唯一的依赖项是datastax驱动程序代码版本2.1.3) 现在可以下载完整代码、启动脚本和配置文件 在伪代码中,我编写了两个不同版本的应用程序,同步版本:Java 异步写入在Cassandra中似乎被破坏了,java,cassandra,Java,Cassandra,在向12节点cassandra(2.1.2)集群写入900万行的批时,我遇到了spark cassandra连接器(1.0.4,1.1.0)的问题。我写的是一致的,读的是一致的,但每次读的行数都不同于900万行(8.865.753、8.753.213等等) 我检查了连接器的代码,没有发现任何问题。然后,我决定独立于spark和连接器编写自己的应用程序来研究这个问题(唯一的依赖项是datastax驱动程序代码版本2.1.3) 现在可以下载完整代码、启动脚本和配置文件 在伪代码中,我编写了两个不同版
try (Session session = cluster.connect()) {
String cql = "insert into <<a table with 9 normal fields and 2 collections>>";
PreparedStatement pstm = session.prepare(cql);
for(String partitionKey : keySource) {
// keySource is an Iterable<String> of partition keys
BoundStatement bound = pstm.bind(partitionKey /*, << plus the other parameters >> */);
bound.setConsistencyLevel(ConsistencyLevel.ALL);
session.execute(bound);
}
}
try(会话=cluster.connect()){
字符串cql=“插入”;
PreparedStatement pstm=会话准备(cql);
for(字符串分区键:keySource){
//keySource是分区键的一个Iterable
BoundStatement bound=pstm.bind(partitionKey/*,>*/);
绑定.setConsistenceLevel(ConsistenceLevel.ALL);
执行(绑定);
}
}
和异步的一个:
try (Session session = cluster.connect()) {
String cql = "insert into <<a table with 9 normal fields and 2 collections>>";
PreparedStatement pstm = session.prepare(cql);
for(String partitionKey : keySource) {
// keySource is an Iterable<String> of partition keys
BoundStatement bound = pstm.bind(partitionKey /*, << plus the other parameters >> */);
bound.setConsistencyLevel(ConsistencyLevel.ALL);
session.execute(bound);
}
}
try (Session session = cluster.connect()) {
List<ResultSetFuture> futures = new LinkedList<ResultSetFuture>();
String cql = "insert into <<a table with 9 normal fields and 2 collections>>";
PreparedStatement pstm = session.prepare(cql);
for(String partitionKey : keySource) {
// keySource is an Iterable<String> of partition keys
while(futures.size()>=10 /* Max 10 concurrent writes */) {
// Wait for the first issued write to terminate
ResultSetFuture future = futures.get(0);
future.get();
futures.remove(0);
}
BoundStatement bound = pstm.bind(partitionKey /*, << plus the other parameters >> */);
bound.setConsistencyLevel(ConsistencyLevel.ALL);
futures.add(session.executeAsync(bound));
}
while(futures.size()>0) {
// Wait for the other write requests to terminate
ResultSetFuture future = futures.get(0);
future.get();
futures.remove(0);
}
}
try(会话=cluster.connect()){
列表未来=新建LinkedList();
字符串cql=“插入”;
PreparedStatement pstm=会话准备(cql);
for(字符串分区键:keySource){
//keySource是分区键的一个Iterable
而(futures.size()>=10/*最多10次并发写入*/){
//等待第一次发出的写操作终止
ResultSetFuture=futures.get(0);
future.get();
删除(0);
}
BoundStatement bound=pstm.bind(partitionKey/*,>*/);
绑定.setConsistenceLevel(ConsistenceLevel.ALL);
futures.add(session.executeAsync(绑定));
}
while(futures.size()>0){
//等待其他写入请求终止
ResultSetFuture=futures.get(0);
future.get();
删除(0);
}
}
最后一个与连接器在没有批量配置的情况下使用的类似
应用程序的两个版本在所有情况下都工作相同,负载较高时除外
例如,当运行同步版本时,9台机器上有5个线程(45个线程)向集群写入900万行,我会在后续读取中找到所有行(使用spark cassandra connector)
如果我以每台机器1个线程(9个线程)运行异步版本,执行速度会快得多,但我无法在后续读取中找到所有行(与spark cassandra连接器出现的问题相同)
在执行期间,代码未引发任何异常
问题的原因可能是什么
我添加了一些其他结果(感谢您的评论):
- 异步版本,9台机器上有9个线程,每个线程有5个并发写入程序(45个并发写入程序):无问题
- 9台机器上90个线程的同步版本(每个JVM实例10个线程):无问题
- 您的异步示例一次执行10次写操作,有9个线程,因此一次执行90次,而您的同步示例一次只执行45次写操作,因此我会尝试将异步降低到相同的速率,以便进行苹果对苹果的比较
您没有说明如何使用异步方法检查异常。我看到您正在使用
,但建议使用future.get()
,如文档中所述: 等待查询返回并返回其结果。这种方法是可行的 通常比Future.get()更方便,因为它:等待 结果是不间断的,因此不会抛出InterruptedException。 返回有意义的异常,而不必处理 执行例外。因此,这是获得未来的首选方式 结果 因此,您可能没有看到异步示例中出现的写异常getunterruptibly()
- 另一种不太可能的可能性是,由于某种原因,您的keySource返回重复的分区键,因此当您进行写入时,其中一些键最终会覆盖以前插入的行,并且不会增加行数。但这也会影响同步版本,所以我说不太可能 我会尝试以较慢的速度编写小于900万的小集,看看问题是否只在一定数量的插入或一定数量的插入时才开始出现。如果插入的数量有影响,那么我怀疑数据中的行键有问题。如果插入速率有影响,那么我会怀疑热点导致写入超时错误
- 另一件需要检查的事情是Cassandra日志文件,以查看是否有任何异常报告