首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有较差插入性能和插入稳定性的Cassandra集群

具有较差插入性能和插入稳定性的Cassandra集群
EN

Stack Overflow用户
提问于 2015-01-12 12:38:15
回答 1查看 5.3K关注 0票数 7

我必须存储大约250个数值每秒,每个客户端,大约是900 K的数字每小时。这可能不是一整天的记录(可能每天5-10个小时),但我将根据客户端id和读取日期来划分数据。最大行长在22-23M左右,这仍然是可管理的。Neverteless,我的计划是这样的

代码语言:javascript
复制
CREATE TABLE measurement (
  clientid text,
  date text,
  event_time timestamp,
  value int,
  PRIMARY KEY ((clientid,date), event_time)
);

密钥空间的复制因子为2,只是为了测试,告密者是GossipingPropertyFileSnitchNetworkTopologyStrategy。我知道复制因子3更符合生产标准。

接下来,我在公司服务器上创建了一个小型集群,三台裸金属虚拟机器,2 CPU x2核,16 of内存和大量空间。我和他们一起在千兆位局域网里。基于节点工具,集群是可操作的。

下面是我用来测试设置的代码:

代码语言:javascript
复制
        Cluster cluster = Cluster.builder()
                .addContactPoint("192.168.1.100")
                .addContactPoint("192.168.1.102")
                .build();
        Session session = cluster.connect();
        DateTime time = DateTime.now();
        BlockingQueue<BatchStatement> queryQueue = new ArrayBlockingQueue(50, true);

    try {

        ExecutorService pool = Executors.newFixedThreadPool(15); //changed the pool size also to throttle inserts

        String insertQuery = "insert into keyspace.measurement (clientid,date,event_time,value) values (?, ?, ?, ?)";
        PreparedStatement preparedStatement = session.prepare(insertQuery);
        BatchStatement batch = new BatchStatement(BatchStatement.Type.LOGGED); //tried with unlogged also

        //generating the entries
        for (int i = 0; i < 900000; i++) { //900000 entries is an hour worth of measurements
            time = time.plus(4); //4ms between each entry
            BoundStatement bound = preparedStatement.bind("1", "2014-01-01", time.toDate(), 1); //value not important
            batch.add(bound);

            //The batch statement must have 65535 statements at most
            if (batch.size() >= 65534) {
                queryQueue.put(batch);
                batch = new BatchStatement();
            }
        }
        queryQueue.put(batch); //the last batch, perhaps shorter than 65535

        //storing the data
        System.out.println("Starting storing");
        while (!queryQueue.isEmpty()) {
            pool.execute(() -> {
                try {

                    long threadId = Thread.currentThread().getId();
                    System.out.println("Started: " + threadId);
                    BatchStatement statement = queryQueue.take();
                    long start2 = System.currentTimeMillis();
                    session.execute(statement);
                    System.out.println("Finished " + threadId + ": " + (System.currentTimeMillis() - start2));
                } catch (Exception ex) {
                    System.out.println(ex.toString());
                }
            });

        }
        pool.shutdown();
        pool.awaitTermination(120,TimeUnit.SECONDS);


    } catch (Exception ex) {
        System.out.println(ex.toString());
    } finally {
        session.close();
        cluster.close();
    }

我是通过阅读这里和其他博客和网站上的帖子来编写代码的。正如我所理解的,客户端使用多个线程是很重要的,这就是我这么做的原因。我还尝试使用异步操作。

最后的结果是,无论我使用哪种方法,一个批处理在5-6秒内执行,虽然它可能需要10秒。如果只输入一个批处理(所以,只有~65k列)或使用一个哑的单线程应用程序,则相同。老实说,我期待的更多。尤其是在我的笔记本电脑上有一个本地实例的情况下,我的性能差不多。

第二个,也许更重要的问题,是我以一种不可预测的方式面对的例外。这两项:

在一致性查询期间,com.datastax.driver.core.exceptions.WriteTimeoutException:卡桑德拉超时(需要一个副本,但只有0确认写入)

com.datastax.driver.core.exceptions.NoHostAvailableException:所有尝试查询失败的主机(尝试: /192.168.1.102:9042 (com.datastax.driver.core.TransportException: /192.168.1.102:9042连接已关闭),/192.168.1.100:9042 (com.datastax.driver.core.TransportException: /192.168.1.100:9042连接已关闭),/192.168.1.101:9042 (com.datastax.driver.core.TransportException: /192.168.1.101:9042连接已关闭)

说到底,我做错什么了吗?应该重新组织加载数据的方式,还是更改方案。我试着减少行长(所以我有12小时的行),但这并没有多大的区别。

==============================更新:

我很粗鲁,忘了粘贴一个我在回答问题后使用的代码示例。这是相当好的工作,但我继续我的研究与KairosDB和二进制传输与Astyanax。看起来我可以在CQL上获得更好的性能,尽管KairosDB在重载时可能会出现一些问题(但我正在做),而且Astyanax对我的口味来说有点冗长。不过,这是密码,我可能弄错了。

信号量槽数在5000以上时对性能没有影响,它几乎是恒定的。

代码语言:javascript
复制
String insertQuery = "insert into keyspace.measurement     (userid,time_by_hour,time,value) values (?, ?, ?, ?)";
        PreparedStatement preparedStatement =     session.prepare(insertQuery);
        Semaphore semaphore = new Semaphore(15000);

    System.out.println("Starting " + Thread.currentThread().getId());
    DateTime time = DateTime.parse("2015-01-05T12:00:00");
    //generating the entries
    long start = System.currentTimeMillis();

    for (int i = 0; i < 900000; i++) { 

        BoundStatement statement = preparedStatement.bind("User1", "2015-01-05:" + time.hourOfDay().get(), time.toDate(), 500); //value not important
        semaphore.acquire();
        ResultSetFuture resultSetFuture = session.executeAsync(statement);
        Futures.addCallback(resultSetFuture, new FutureCallback<ResultSet>() {
            @Override
            public void onSuccess(@Nullable com.datastax.driver.core.ResultSet resultSet) {

                semaphore.release();
            }

            @Override
            public void onFailure(Throwable throwable) {
                System.out.println("Error: " + throwable.toString());
                semaphore.release();
            }
        });
        time = time.plus(4); //4ms between each entry
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-12 13:14:26

您使用未记录批处理的结果是什么?您确定要使用批处理语句吗?https://medium.com/@foundev/cassandra-batch-loading-without-the-batch-keyword-40f00e35e23e

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27902232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档