Cassandra读取性能低,SSTable计数高

时间:2015-03-18 20:29:05

标签: cassandra bigdata data-modeling cassandra-2.0 datastax

我正在构建一个处理非常大的数据的应用程序(超过300万)。我是cassandra的新手,我使用5节点cassandra集群来存储数据。我有两个列族

Table 1 : CREATE TABLE keyspace.table1 (
    partkey1 text,
    partkey2 text,
    clusterKey text,
    attributes text,
    PRIMARY KEY ((partkey1, partkey2), clusterKey1)
) WITH bloom_filter_fp_chance = 0.01
    AND caching = '{"keys":"ALL", "rows_per_partition":"NONE"}'
    AND comment = ''
    AND compaction = {'min_threshold': '4', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32'}
    AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99.0PERCENTILE';

Table 2 : CREATE TABLE keyspace.table2 (
    partkey1 text,
    partkey2 text,
    clusterKey2 text,
    attributes text,
    PRIMARY KEY ((partkey1, partkey2), clusterKey2)
) WITH bloom_filter_fp_chance = 0.01
    AND caching = '{"keys":"ALL", "rows_per_partition":"NONE"}'
    AND comment = ''
    AND compaction = {'min_threshold': '4', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32'}
    AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99.0PERCENTILE';

注意:clusterKey1和clusterKey2是随机生成的UUID的

我关注的是nodetool cfstats 我在Table1上获得了具有统计数据的良好吞吐量:

  • SSTable count:2
  • 使用的空间(总计):365189326
  • 快照使用的空间(总计):435017220
  • SSTable Compression Ratio:0.2578485727722293
  • 可记忆细胞数:18590
  • 可记忆的数据大小:3552535
  • 可记忆开关数:171
  • 本地读取次数:0
  • 本地读取延迟:NaN ms
  • 本地写入次数:2683167
  • 本地写入延迟:1.969 ms
  • 待续费:0
  • 布隆过滤器误报:0
  • 布隆过滤器错误率:0.00000
  • 使用Bloom过滤器空间:352

对于table2,我使用stats读取性能非常糟糕:

  • SSTable count:33
  • 使用的空间(现场):212702420
  • 使用的空间(总计):212702420
  • 快照使用的空间(总计):262252347
  • SSTable Compression Ratio:0.1686948750752438
  • 可记忆细胞计数:40240
  • 可记忆的数据大小:24047027
  • 可记忆开关数:89
  • 本地阅读次数:24027
  • 本地读取延迟:0.580 ms
  • 本地写入次数:1075147
  • 本地写入延迟:0.046 ms
  • 待续费:0
  • 布隆过滤器误报:0
  • 布隆过滤器错误率:0.00000
  • 使用Bloom过滤器空间:688

我想知道为什么table2正在创建33个SSTables,为什么它的读取性能非常低。谁能帮助我弄清楚我在这里做错了什么?

这是我查询表格的方式:

 BoundStatement selectStamt;
if (selectStamt == null) {
            PreparedStatement prprdStmnt = session
                    .prepare("select * from table2 where clusterKey1 = ? and partkey1=? and partkey2=?");
            selectStamt = new BoundStatement(prprdStmnt);
        }
        synchronized (selectStamt) {
            res = session.execute(selectStamt.bind("clusterKey", "partkey1", "partkey2"));
        }

在另一个主题中,我正在以不同的方式对此表进行一些更新操作。

在测量吞吐量的情况下,我测量每秒处理的记录数,其处理仅为50-80 rec。

3 个答案:

答案 0 :(得分:3)

当您拥有大量SSTable时,在这些SSTable中分发数据非常重要。由于您使用的是SizeTieredCompactionStrategy,因此当有4个相同大小的SSTable时,SSTables会被压缩和合并。

如果您经常在不同时间更新同一分区内的数据,那么您的数据很可能会分散在许多SSTable上,这会降低性能,因为您的SSTable会有多次读取。

在我看来,确认这一点的最佳方法是执行cfhistograms on your table

nodetool -h localhost cfhistograms keyspace table2

根据您安装的cassandra版本,输出会有所不同,但它将包含为给定读取操作读取的SSTable数量的直方图。

如果您经常在不同时间更新同一分区中的数据,可以考虑使用LeveledCompactionStrategy(When to use Leveled Compaction)。 LCS会将同一分区中的数据保存在同一个SSTable中,从而大大提高读取性能,代价是更多的磁盘I / O进行压缩。根据我的经验,如果你的读写比率很高,那么额外的压缩磁盘I / O会比读取性能更好。


编辑:关于您关于吞吐量问题的问题,有许多因素限制了您的吞吐量。

  1. 一个可能的大问题是,除非您有多个线程同时进行相同的查询,否则您将按顺序(一次一个)发出请求。通过这样做,您严重限制了吞吐量,因为在您收到Cassandra的回复之前无法发送另一个请求。此外,由于您正在selectStmt上进行同步,即使此代码由多个线程执行,也无论如何一次只能执行一个请求。您可以通过让多个工作线程为您提出请求(如果您还没有这样做),甚至更好的用户executeAsync来异步执行许多请求,从而显着提高吞吐量。有关请求流程如何在驱动程序中工作以及如何有效地使用驱动程序进行许多查询的说明,请参阅Asynchronous queries with the Java driver
  2. 如果您每次进行查询时都执行相同的代码,则可以通过调用' session.prepare'来创建额外的往返行程。每次都要创建PreparedStatement。 session.prepare向cassandra发送请求以准备您的语句。您只需执行一次,每次进行查询时都可以重复使用PreparedStatement。如果你的语句为空检查,你可能已经这样做了(不能在没有更多代码的情况下告诉你)。
  3. 不是重新使用selectStmt并对其进行同步,而是从每次进行查询时使用的单个PreparedStatement创建一个新的BoundStatement。这样就根本不需要同步。

答案 1 :(得分:2)

除了switching compaction strategies(这很贵,你会在改变后坚持一段时间),正如Andy建议肯定会帮助你的阅读表现,你也可以调整你当前的压缩策略试图摆脱一些碎片:

  1. 如果你有未决的压缩(nodetool compactionstats) - 那么试着通过增加压缩限制来赶上。将并发压缩器保持在你的CPU内核的1/2,以避免压缩占用所有内核。
  2. 增加铲斗尺寸(增加bucket_high,降低铲斗) - 指示sstables的大小必须与压缩在一起的程度。
  3. Drop Compaction threshold - 指示在压缩发生之前桶中必须装入多少个sstables。
  4. 有关2和3的详细信息,请查看compaction subproperties

    注意:不要使用nodetool compact。这将把整个表格放在一个巨大的sstable中,你将一次松开压缩切片的好处。

    1. 如遇紧急情况,请使用JMX - >强制用户定义压缩以强制轻微压缩

答案 2 :(得分:0)

你有很多SSTable和慢读。您应该做的第一件事是找出每个SELECT读取多少SSTable。

最简单的方法是检查相应的MBean:在MBean域" org.apache.cassandra.metrics"你找到你的密钥空间,在它下面是你的表,然后是SSTablesPerReadHistorgram MBean。 Cassandra记录最小值,最大值,平均值和百分位数。

SSTablesPerReadHistorgram中第99个百分位数的一个非常好的值是1,这意味着您通常只能从一个表中读取。如果数量与SSTable的数量一样高,Cassandra正在检查所有SSTable。在后一种情况下,您应该仔细检查您的SELECT,无论您是否对整个主键进行选择。