为什么使用 ParparedStatement、BoundStatement、Session.executeAsync 和 ResultSetFuture 的应用程序消耗这么高 CPU?

why a application using ParparedStatement, BoundStatement, Session.executeAsync and ResultSetFuture consuming such high CPU?

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

    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使用率高了最后一次,写多了甚至写失败.

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

实际上,您一次提交了 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