在Cassandra中使用LCS时会延迟清除墓碑的原因

rei*_*kje 2 cassandra

在C * 1.2.x集群中,我们有7个键空间,每个键空间包含一个使用宽行的列族。cf使用LCS。我定期在行中进行删除。最初,每一行每天最多可以包含1个条目。超过3个月的条目将被删除,并且每周最多保留1条条目。我已经运行了几个月,但是并没有真正回收磁盘空间。我需要调查原因。对我来说,墓碑似乎还没有被清除。每个键空间都有大约1300个sstable文件(* -Data.db),每个文件的大小约为130 Mb(sstable_size_in_mb为128)。每个CF中的GC宽限秒为864000。未指定tombstone_threshold,因此应默认为0.2。我应该怎么看才能找出为什么不回收磁盘空间?

min*_*uib 5

我之前在这里的cassandra邮件列表中回答了类似的问题

为了进一步详细说明,至关重要的是,您应该理解一般的“ 分层压缩策略”和“ leveldb”(考虑到正常的写入行为)

总结以上内容:

  • 数据存储组织为“级别”。每个级别比其下的级别大10倍。级别0的文件具有重叠范围。较高级别的文件在每个级别中没有重叠的范围。
  • 新写操作将存储为进入级别0的新sstable。每隔一段时间,level0中的所有sstable都会“压缩”到1级sstable,然后向上压缩到2级sstables等。
  • 读取给定键将执行〜N次读取,N是树中的级别数(这是数据集总大小的函数)。级别0的sstables均被扫描(因为没有约束,每个sstable都具有与兄弟姐妹不重叠的范围)。级别1和更高级别的sstables没有重叠范围,因此数据库知道级别1中的哪个1确切sstable涵盖了您要求的密钥范围,级别2相同...
  • LCS树在cassandra中的布局存储在一个json文件中,您可以轻松检查它-您可以在与keyspace + ColumnFamily的sstables相同的目录中找到它。这是我的一个节点的示例(结合jq工具+ awk进行总结):

    $ cat users.json | jq ".generations[].members|length" | awk '{print "Level", NR-1, ":", $0, "sstables"}'
    Level 0 : 1 sstables
    Level 1 : 10 sstables
    Level 2 : 109 sstables
    Level 3 : 1065 sstables
    Level 4 : 2717 sstables
    Level 5 : 0 sstables
    Level 6 : 0 sstables
    Level 7 : 0 sstables
    
    Run Code Online (Sandbox Code Playgroud)

正如您已经注意到的,sstable的大小通常相等,因此您可以看到每个级别的大小大约是前一个级别的10倍。我希望在上面的节点中能够满足〜5 sstable读取中的大多数读取操作。一旦我添加了足够的数据以使Level 4达到10000 sstable,并且Level 5开始被填充,我的读取延迟就会稍有增加,因为每次读取都会产生1 sstable读取以满足。(在切线上,cassandra提供了桶状直方图供您检查所有这些统计信息)。

有了以上这些,让我们逐步完成一些操作:


  • 我们发出一个写[“ bob”] [“ age”] =30。这将输入level0。通常在它压缩到第1级之后不久。慢慢地,它将花时间在每个级别上,但是随着更多的写入进入系统,它将向上迁移到最高级别N
  • 我们发布[[bob]] [“ age”]的读物。然后,DB可以检查从最低到最高的每个级别-一旦找到可以返回的数据。如果达到最高级别但尚未找到它,则该节点上不存在数据。如果在任何级别找到逻辑删除,它都可以返回“未找到”,因为数据已被删除

  • 我们发出一个删除[“ bob”] [“ age”]。这将以普通写入方式输入level0,并带有特殊值“ column tombstone”。通常在它压缩到第1级之后不久。慢慢地,它将花费时间在每个级别上,但是随着更多的写入进入系统,它将向上迁移到最高级别N。在每次压缩期间,如果将一起压缩的sstable有一个墓碑(例如在l1中)和一个实际值(例如l2中的“ 30”),逻辑删除“吞噬”该值并影响该级别的逻辑删除。但是,该逻辑删除尚不能丢弃,必须坚持下去,直到有机会将其压缩到每个级别为止,直到达到最高级别为止–这是确保L2的年龄= 30,L3的年龄= 29岁,而L4的年龄更是28岁,他们所有人都有机会被墓碑摧毁。只有当墓碑达到最高水平时,它才能真正被完全丢弃
  • 我们发布[[bob]] [“ age”]的读物。然后,DB可以检查从最低到最高的每个级别-一旦找到可以返回的数据。如果达到最高级别但尚未找到它,则该节点上不存在数据。如果在任何级别找到逻辑删除,它都可以返回“未找到”,因为数据已被删除

  • 我们发出一个删除[“ bob”]。这将以普通写入方式输入level0,并带有特殊值“行逻辑删除”。它将遵循与上述列级逻辑删除相同的逻辑,除非它与行“ bob”下任何列的任何现有数据冲突,它将丢弃它。
  • 我们发布[[bob]] [“ age”]的读物。然后,DB可以检查从最低到最高的每个级别-一旦找到可以返回的数据。如果达到最高级别但尚未找到它,则该节点上不存在数据。如果在任何级别找到逻辑删除,它都可以返回“未找到”,因为数据已被删除

我希望这能回答您的问题,关于为什么cassandra中的删除(尤其是使用LCS的删除)实际上会占用空间而不是释放空间(至少在最初是这样)。逻辑删除所附加的行+列的大小(实际上可能比您拥有简单值的情况下要删除的值大)。

这里的关键点是,在cassandra实际丢弃它们之前,它们必须遍历所有级别直到最高级别L,而这种冒泡的主要驱动力是总写入量。