2016-09-22 105 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

在我研究之前,你的結果集有多大? (每行的列數,每個查詢的行數)? –