【问题标题】:Cassandra low read performance with high SSTable countCassandra 低读取性能和高 SSTable 计数
【发布时间】:2015-05-21 19:49:36
【问题描述】:

我正在构建一个处理非常大的数据(超过 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 计数:2
  • 已用空间(总计):365189326
  • 快照使用的空间(总计):435017220
  • SSTable 压缩比:0.2578485727722293
  • 内存单元数:18590
  • Memtable 数据大小:3552535
  • Memtable 开关数:171
  • 本地读取计数:0
  • 本地读取延迟:NaN 毫秒
  • 本地写入计数:2683167
  • 本地写入延迟:1.969 毫秒
  • 待刷新:0
  • 布隆过滤器误报:0
  • 布隆过滤器误报率:0.00000
  • 使用的布隆过滤器空间:352

对于 table2,我的统计数据读取性能非常差:

  • SSTable 计数:33
  • 已用空间(实时):212702420
  • 已用空间(总计):212702420
  • 快照使用的空间(总计):262252347
  • SSTable 压缩比:0.1686948750752438
  • 记忆单元数:40240
  • Memtable 数据大小:24047027
  • Memtable 开关数:89
  • 本地读取计数:24027
  • 本地读取延迟:0.580 毫秒
  • 本地写入计数:1075147
  • 本地写入延迟:0.046 毫秒
  • 待刷新:0
  • 布隆过滤器误报:0
  • 布隆过滤器误报率:0.00000
  • 使用的布隆过滤器空间: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 条记录。

【问题讨论】:

  • 低(亚毫秒)“本地读取延迟”是件好事。
  • 是的,500 微秒会让几乎所有高频交易者都开心:)。尽管 cfstats(取决于我认为的版本)在执行后确实会重置,但 Rijo 看到的性能可能比这显示的要差。

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


【解决方案1】:

当您拥有大量 SSTable 时,您的数据在这些 SSTable 之间的分布非常重要。由于您使用的是 SizeTieredCompactionStrategy,当有 4 个大小相同的 SSTables 时,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。这种方式根本不需要同步。

【讨论】:

  • 感谢您的回复...我的读取速度非常低,因为每秒读取不到 50 次。你知道为什么要为 table to 创建更多的 SSTable,因为它的结构与 table1 相似吗?
  • 我想我需要更多信息才能充分回答这个问题。您能否更新您的问题以包括以下内容:1)您正在做什么确切的查询? 2)您如何进行查询(什么客户)? 3)您是连续进行查询(一个接一个),还是异步提交? 4) 你如何衡量你的吞吐量?
  • 安迪·托尔伯特,我已经更新了我的问题。可以看看吗?
  • 谢谢!有没有办法查看为此表创建了多少分区?
  • @RioJoseph 我已经更新了我的答案。关于# of partitions,有很多方法可以做到这一点,但它永远不会是一个便宜的查询。对于测试,您可以进行范围查询并计算行数,即:select count(*) from keyspace.table2;。您可以使用类似 spark 连接器的东西来有效地进行计数查询。 Cassandra 是一个分布式系统,因此要收集这些信息,您必须查询所有范围,所以它不会很便宜。
【解决方案2】:

除了switching compaction strategies(这很昂贵,更改后您会努力压缩一段时间),正如 Andy 所建议的,这肯定会提高您的读取性能,您还可以调整当前的压缩策略以尝试摆脱一些碎片化:

  1. 如果您有待处理的压缩 (nodetool compactionstats) -- 然后尝试通过增加压缩限制来赶上。将并发压缩器保持在 CPU 内核的 1/2,以避免压缩占用所有内核。
  2. 增加存储桶大小(增加存储桶高,降低存储桶低)- 指示要压缩在一起的 sstable 的大小必须达到何种程度。
  3. Drop Compaction 阈值 - 规定在进行压缩之前必须在存储桶中放入多少 sstable。

有关 2 和 3 的详细信息,请查看compaction subproperties

注意:不要使用 nodetool compact。这会将整个表放在一个巨大的稳定中,您将失去一次压缩切片的好处。

  1. 在紧急情况下使用 JMX --> 强制用户定义的压缩以强制进行次要压缩

【讨论】:

  • 感谢您的回复...我的读取速度非常低,因为每秒读取不到 50 次。你知道为什么要为 table to 创建更多的 SSTable,因为它的结构与 table1 相似吗?
  • 这是调整 SizeTieredCompaction 的一个好点。有时 LeveledCompaction 被用作“一刀切”(我对此感到非常内疚),但情况并非总是如此。
【解决方案3】:

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

最简单的方法是检查相应的 MBean:在 MBean 域“org.apache.cassandra.metrics”中,您可以找到您的键空间,在其下方是您的表,然后是 SSTablesPerReadHistorgram MBean。 Cassandra 记录最小值、最大值、平均值以及百分位数。

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

【讨论】:

    猜你喜欢
    • 2017-02-13
    • 2018-09-15
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 2018-03-20
    • 2011-06-15
    • 2015-12-16
    • 2023-03-27
    相关资源
    最近更新 更多