2016-09-22 101 views
0

使用datastax cassandra驱动程序(3.0)可以看到一个奇怪的行为。我创建了一个新的集群,然后我使用同一个集群对象启动了一组线程。如果我保持线程为1或2,我会看到5ms的平均提取时间,但是如果我将线程数增加到60,则提取时间会增加到200ms(每个线程)。奇怪的是,如果我让60个线程应用程序运行,并且我在同一台机器上启动另一个只有1个线程的进程,那么该单线程应用程序的提取时间又是5ms。所以这似乎与客户有关。我多次重复相同的测试以避免缓存冷启动问题。 这里是集群对象是如何配置:Cassandra java驱动程序 - 使用多线程提取数据时的高延迟

PoolingOptions poolingOptions = new PoolingOptions(); 
    poolingOptions 
     .setConnectionsPerHost(HostDistance.LOCAL, parallelism, parallelism+20) 
     .setConnectionsPerHost(HostDistance.REMOTE, parallelism, parallelism+20) 
     .setMaxRequestsPerConnection(HostDistance.LOCAL, 32768) 
     .setMaxRequestsPerConnection(HostDistance.REMOTE, 2000); 

    this.cluster = Cluster.builder() 
      .addContactPoints(nodes) 
      .withRetryPolicy(DowngradingConsistencyRetryPolicy.INSTANCE) 
      .withReconnectionPolicy(new ConstantReconnectionPolicy(100L)) 
      .withLoadBalancingPolicy(new TokenAwarePolicy(DCAwareRoundRobinPolicy.builder().build())) 
      .withCompression(Compression.LZ4) 
      .withPoolingOptions(poolingOptions) 
      .withProtocolVersion(ProtocolVersion.V4) 
      .build(); 

有谁经历过同样的问题吗?这似乎是一个客户端配置问题。也许Netty有一些额外的缺失配置?

更新1 什么应用程序在做使用查询等提取数据的块:

select * from table where id=? and ts>=? and ts<? 

所以我有60个线程并行提取这些数据。 id是分区键。每个查询由线程执行如下:

//Prepare statement 
PreparedStatement stmt = ... get the prepared statment cached 
BoundStatement bstmt = stmt.bind(...) 
//Execute query 
long te1 = System.nanoTime();  
ResultSet rs = this.session.execute(bstmt); 
long te2 = System.nanoTime(); 
//Fetch... 
Iterator<Row> iterator = rs.iterator(); 
while (!rs.isExhausted() && iterator.hasNext()) { .... } 

会话是一个并共享交叉所有线程。我测量的是session.execute()方法调用的平均时间。

谢谢!

更新2 下面是schema定义

CREATE TABLE d_t (
    id bigint, 
    xid bigint, 
    ts timestamp, 
    avg double, 
    ce double, 
    cg double, 
    p double, 
    w double, 
    c double, 
    sum double, 
    last double, 
    max double, 
    min double, 
    p75 double, 
    p90 double, 
    p95 double, 
    squad double, 
    sumq double, 
    wavg double, 
    weight double, 
    PRIMARY KEY ((id), xid, ts) 
) WITH CLUSTERING ORDER BY (xid DESC, ts DESC) 
and compaction = {'class': 'SizeTieredCompactionStrategy'} 
and gc_grace_seconds=86400 
and caching = { 'keys' : 'ALL', 'rows_per_partition':'36000' } 
and min_index_interval = 2 
and max_index_interval = 20; 

更新3 也试图与

.setMaxRequestsPerConnection(HostDistance.LOCAL, 1) 
.setMaxRequestsPerConnection(HostDistance.REMOTE, 1) 

没有变化

回答

0

最后,我认为这将取决于什么你的代码正在做。你能分享一个例子吗?

关于增加延迟,你如何衡量这个?根据您的语句:

奇怪的是,如果我让60个线程应用程序运行,我开始在同一台机器的另一个进程上只有1个线程,提取时间为单线程应用程序再次为5ms。

60个并发请求实际上并不是太多,一般情况下,您不需要使用datastax java驱动程序执行每个线程请求。您可以使用单个应用程序线程实现高吞吐量,因为驱动程序使用的netty事件循环组将完成大部分工作。

C *使用的本地协议允许每个连接有很多请求。正如你在这里配置的那样,每个连接最多可达32768个并发请求。实际上,根本不需要触及此配置,因为默认情况下(每个连接1000个请求)是明智的,因为在实践中,C *不会从cassandra.yaml(缺省为128)处理超过native_transport_max_threads的时间并排队休息。

因此,您不需要为每个主机建立多个连接。每个主机的1个核心连接的默认值应该足够用于60个并发请求。增加每台主机的连接数对你来说没有多大作用,而且在分析中,我发现每台主机的吞吐量超过8个,吞吐量高(成千上万的并发请求),吞吐量每台主机超过16个连接的吞吐量会越来越差,尽管你的里程数可能因环境而异。

综上所述,我建议不要将PoolingOptions配置为超出默认值,除非可能将核心和最大值设置为8,以便您尝试实现更高吞吐量(> 10k请求/秒)的情况。

+0

谢谢!我用一个应用程序正在做的例子更新了这个问题。问候 – RJtokenring

+0

谢谢!我会更新我的答案。 –

+0

在我研究之前,你的结果集有多大? (每行的列数,每个查询的行数)? –