在Cassandra中使用LCS时,什么延迟了墓碑清除

时间:2015-01-09 14:31:27

标签: 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。我应该看看为什么没有回收磁盘空间?

3 个答案:

答案 0 :(得分:4)

我之前在cassandra邮件列表here

上回答了类似的问题

为了进一步阐述,一般来说理解Levelled Compaction Strategyleveldb(给定正常的写行为)至关重要

总结以上内容:

  • 数据存储被组织为"级别"。每个级别比其下的级别大10倍。级别0中的文件具有重叠范围。较高级别的文件在每个级别内没有重叠范围。
  • 新写入被存储为新的sstables,进入0级。每隔一段时间,level0中的所有sstables都被"压缩"向上升至1级sstables,然后将它们向上压缩到2级sstables等。
  • 读取给定键将执行~N次读取,N是树中级别的数量(这是总数据集大小的函数)。级别0 sstables都被扫描(因为没有约束,每个约束与兄弟姐妹都有不重叠的范围)。然而,1级和更高级别的sstables没有重叠范围,因此DB知道level1中哪1个精确sstable覆盖了你要求的密钥的范围,对于2级等也是如此......
  • cassandra中LCS树的布局存储在一个您可以轻松检查的json文件中 - 您可以在与keypace + 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
    

正如您所指出的那样,sstables通常具有相同的大小,因此您可以看到每个级别大约是前一级别的10倍。我希望在上面的节点中能够满足~5 sstable读取中的大多数读操作。一旦我为Level 4添加足够的数据以达到10000 sstables并且Level 5开始填充,我的读取延迟将略微增加,因为每次读取将产生1次sstable读取以满足。 (在切线上,cassandra提供了一个分块的直方图,供您检查所有这些统计数据)。

完成上述操作后,让我们来完成一些操作:


  • 我们发出一个写[" bob"] [" age"] = 30.这将进入level0。通常很快就会被压缩到level1。慢慢地,它会在每个级别上花费时间,但随着更多写入进入系统,它将向上迁移到最高级别N
  • 我们发出[" bob"] ["年龄"]的阅读材料。然后,DB可以从最低到最高检查每个级别 - 一旦找到可以返回它的数据。如果它达到最高级别并且尚未找到它,则该节点上的数据不存在。如果在任何级别找到墓碑,它都可以返回"未找到"因为数据已被删除

  • 我们发出删除[" bob"] ["年龄"]。这将使用特殊值"列墓碑"输入level0作为正常写入。通常很快就会被压缩到level1。慢慢地,它会在每个级别上花费时间,但随着更多的写入进入系统,它将向上迁移到最高级别N.在每次压缩期间,如果被压缩的sstables有一个墓碑(例如l1)和一个实际值(例如" 30"在l2中),墓碑"吞噬"值并影响该级别的逻辑删除。然而,tomstone还不能被丢弃,并且必须坚持直到它有机会紧贴每个级别直到达到最高级别 - 这是确保如果L2年龄= 30,L3年龄较大=的唯一方法29,而L4的年龄甚至更大,年龄= 28岁,所有人都有机会被墓碑摧毁。只有当墓碑达到最高级别时才能完全丢弃
  • 我们发出[" bob"] ["年龄"]的阅读材料。然后,DB可以从最低到最高检查每个级别 - 一旦找到可以返回它的数据。如果它达到最高级别并且尚未找到它,则该节点上的数据不存在。如果在任何级别找到墓碑,它都可以返回"未找到"因为数据已被删除

  • 我们发出删除[" bob"]。这将输入level0作为正常写入,具有特殊值" row tombstone"。它将遵循与上述列级逻辑删除相同的逻辑,除非它与行" bob"下的任何列的任何现有数据发生冲突。它丢弃它。
  • 我们发出[" bob"] ["年龄"]的阅读材料。然后,DB可以从最低到最高检查每个级别 - 一旦找到可以返回它的数据。如果它达到最高级别并且尚未找到它,则该节点上的数据不存在。如果在任何级别找到墓碑,它都可以返回"未找到"因为数据已被删除

我希望这可以回答你的问题,为什么cassandra中的删除,特别是LCS,实际上消耗空间而不是释放空间(至少在最初阶段)。墓碑附加到自身的行+列有一个大小(实际上可能大于您在具有简单值时尝试删除的值的大小)。

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

答案 1 :(得分:0)

感谢LCS的精彩解释,@ minaguib。我认为Datastax的声明具有误导性,至少对我而言

C:\Program Files\Oracle\VirtualBox

取决于我们如何定义“过时的行”。如果“废弃的行”被定义为所有应该压缩的行,在您的示例中,这些“过时行”将是年龄= 30,年龄= 29,年龄= 28。我们最终可能浪费(N-1) )/ N空间,因为这些“年龄”可以处于不同的水平。

答案 2 :(得分:0)

我希望在这里放魔术酱。

我们将在整个集群中滚动地进行JMX触发的LCS-> STCS-> LCS。压缩策略的转换迫使LCS结构化的sstables重新构造并应用逻辑删除(在我们的cassandra版本中,我们无法强制执行LCS压缩)。

有一些nodetool命令可以强制在表之间进行压缩,但这可能会破坏LCS。也有nodetool命令来重新分配sstable的级别,但是同样,如果您破坏了它的结构,这可能会使LCS变得愚蠢。

真正应该发生的是,应将行逻辑删除放置在单独的sstable类型中,该类型可以针对“ data” sstables进行独立处理,以进行清除。逻辑删除sstable <->数据稳定的处理不会删除逻辑删除的sstable,而只是从逻辑删除的sstable中删除在处理/解析/修剪数据之后不再需要的逻辑删除。也许可以将它们归类为“ PURGE”墓碑,以进行大规模数据删除,而不是将更多临时的“ DELETE”墓碑与数据混合。但是谁知道何时将其添加到Cassandra中。