Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 异步写入在Cassandra中似乎被破坏了_Java_Cassandra - Fatal编程技术网

Java 异步写入在Cassandra中似乎被破坏了

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) 现在可以下载完整代码、启动脚本和配置文件 在伪代码中,我编写了两个不同版

在向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个线程):无问题
在同一个会话上,异步写入和多个并发写入程序(45和5)并发写入似乎开始出现问题。

有几种可能性:

  • 您的异步示例一次执行10次写操作,有9个线程,因此一次执行90次,而您的同步示例一次只执行45次写操作,因此我会尝试将异步降低到相同的速率,以便进行苹果对苹果的比较

    您没有说明如何使用异步方法检查异常。我看到您正在使用
    future.get()
    ,但建议使用
    getunterruptibly()
    ,如文档中所述:

    等待查询返回并返回其结果。这种方法是可行的 通常比Future.get()更方便,因为它:等待 结果是不间断的,因此不会抛出InterruptedException。 返回有意义的异常,而不必处理 执行例外。因此,这是获得未来的首选方式 结果

    因此,您可能没有看到异步示例中出现的写异常

  • 另一种不太可能的可能性是,由于某种原因,您的keySource返回重复的分区键,因此当您进行写入时,其中一些键最终会覆盖以前插入的行,并且不会增加行数。但这也会影响同步版本,所以我说不太可能

    我会尝试以较慢的速度编写小于900万的小集,看看问题是否只在一定数量的插入或一定数量的插入时才开始出现。如果插入的数量有影响,那么我怀疑数据中的行键有问题。如果插入速率有影响,那么我会怀疑热点导致写入超时错误

  • 另一件需要检查的事情是Cassandra日志文件,以查看是否有任何异常报告

附录:2014年12月30日

我尝试使用Cassandra 2.1.2和driver 2.1.3的示例代码再现症状。我使用了一个带有递增数字键的表,这样我就可以看到数据中的缺口。我做了很多异步插入(10个线程中每个线程一次插入30个,全部使用一个全局会话)。然后我对表进行了“selectcount(*)”,实际上它报告的表中的行数比预期的少。然后我做了一个“select*”并将行转储到一个文件中,并检查是否缺少键。它们似乎是随机分布的,但当我查询缺少的单个行时,发现它们实际上存在于表中。然后我注意到每次我做一个“select count(*)时,它都会返回一个不同的数字,因此它似乎给出了表中行数的近似值,而不是实际数

所以我