为什么一个应用程序使用ParparedStatement,BoundStatement,Session.executeAsync和ResultSetFuture消耗如此高的CPU?

时间:2015-12-30 01:44:16

标签: java cassandra datastax-java-driver

我需要在3个节点的Cassandra(2.1.11)集群中写入近1000万条记录,复制因子为1, 我的步骤几乎与datastax的Java Driver:

相同
    String  insert_query = "insert into " + keyspace + "." + tblName
            + " (a, b, c, d,"
            + "e, f, g, h, i, j,"
            + "k, l, m, n)  VALUES "
            + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
   List<ResultSetFuture> futures = new ArrayList<ResultSetFuture>();
   PreparedStatement statement = session.prepare(insert_query);
   BoundStatement bind = null;
   int max = 5000000 or 6000000 or 7000000 
   for(int i = 0; i < max ; i++) {
                bind = statement.bind(
                        id,
                        ...                 
                        null,
                        null,
                        null
                );
            ResultSetFuture resultSetFuture = session.executeAsync(bind);
            futures.add(resultSetFuture);
  } //for
 for(ResultSetFuture future : futures){
            future.getUninterruptibly(15000, TimeUnit.MILLISECONDS);
  }

然后,我的应用程序在具有16个核心的机器下运行,我监视进程'CPU消耗:

PID   USER     PR  NI  VIRT   RES  SHR S  %CPU    %MEM  TIME+     COMMAND
25502 pengcz   20  0   30.8g  27g  19m S  1263.7  25.8  104:28.82    java 

我发现CPU使用率太高(1263.7%),我发现高CPU使用时间更长,或者如果我写了更多记录,甚至写入失败。

我不知道我的错误步骤会导致这种情况吗?任何建议将不胜感激!

1 个答案:

答案 0 :(得分:3)

您实际上是在同时提交5,6或700万个请求,然后等待所有请求立即完成。由于您构建的期货列表最多可达请求数,因此您不仅要提交许多请求,还要使用大量内存跟踪这些响应。我想在不等待响应的情况下提交许多请求会产生大量的CPU生成请求有效负载并将其写入网络,此外还有不断增加的GC压力使这些期货保持在一个巨大的列表中。

你应该做的只是一次只有这么多的飞行请求(500可能?),等待它们完成,然后提交下一组等等。肯定有更好和更优化的技术,而且这也不能很好地处理错误情况,但它应该降低你的内存占用并防止你用许多请求锤击C *。以下是一个示例:

    String insert_query = "insert into " + keyspace + "." + tblName
            + " (a, b, c, d,"
            + "e, f, g, h, i, j,"
            + "k, l, m, n)  VALUES "
            + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
    List<ResultSetFuture> futures = new ArrayList<ResultSetFuture>();
    PreparedStatement statement = session.prepare(insert_query);
    BoundStatement bind = null;
    int max = 1000000;

    for (int i = 0; i < max; i++) {
        bind = statement.bind(i,
                null,
                null,
                null
        );
        ResultSetFuture resultSetFuture = session.executeAsync(bind);
        futures.add(resultSetFuture);

        if (futures.size() % 500 == 0 || i == max - 1) {
            for (ResultSetFuture future : futures) {
                future.getUninterruptibly(15000, TimeUnit.MILLISECONDS);
            }
            futures.clear();
        }
    }

如需进一步指导,请查看Asynchronous queries with the Java driver