Kafka没有用墓碑删除密钥

时间:2017-10-08 15:18:55

标签: apache-kafka

我使用以下属性

创建一个kafka主题

min.cleanable.dirty.ratio = 0.01,delete.retention.ms = 100,segment.ms = 100,cleanup.policy =紧凑

假设我按顺序插入k-v对 1111:1,1111:2,1111:null,2222:1 现在发生的事情是除了上一条消息,日志压缩在其余消息上运行并清除前两个但保留 1111:null

根据文件,

Kafka log compaction also allows for deletes. A message with a key and a null payload acts like a tombstone, a delete marker for that key. Tombstones get cleared after a period.

所以,我希望当达到delete.retention.ms时,空标记应该删除密钥 1111

的消息

我有两个问题 - 为什么墓碑标记不起作用?为什么压缩会忽略最后一条消息?

这就是server.properties文件所具有的 -

log.retention.ms=100
log.retention.bytes=1073741824
log.segment.bytes=1073741824
log.retention.check.interval.ms=100
log.cleaner.delete.retention.ms=100
log.cleaner.enable=true
log.cleaner.min.cleanable.ratio=0.01

3 个答案:

答案 0 :(得分:10)

墓碑记录的设计保留时间更长。原因是,经纪人不追踪消费者。假设消费者在阅读第一条记录后离线一段时间。在消费者瘫痪的同时,日志压缩开始了。如果日志压缩将删除逻辑删除记录,则消费者将永远不会了解记录被删除的事实。如果使用者实现了缓存,则可能会发生永远不会删除记录的情况。因此,墓碑保存的时间更长,以允许离线消费者接收所有墓碑以进行本地清理。

仅在delete.retention.ms之后删除墓碑(默认值为1天)。注意:这是主题级别配置,并且没有代理级别配置。因此,如果要更改它,则需要为每个主题设置配置。

答案 1 :(得分:3)

压缩主题有两部分:

1)清洁部分:由kafka清洁剂至少清理一次的kafka日志部分。

2)肮脏的部分:kafka日志的部分直到现在才被kafka清洁剂清理过一次。卡夫卡保持着肮脏的抵消。偏移> =脏偏移的所有消息都属于脏部分。

注意:Kafka清洁剂清洁所有段(无论段是否在清洁/脏污部分)并在每次脏比达到min.cleanable.dirty.ratio时重新复制它们。

明智地删除了墓碑。如果段满足以下条件,则段中的逻辑删除将被删除:

  1. 细分应位于日志的清理部分。

  2. 段的最后修改时间应为< =(包含带偏移量的消息的段的最后修改时间=(脏偏移量 - 1)) - delete.retention.ms。

  3. 很难详细说明第二点,但简单来说,第二点暗示=>段大小应等于log.segment.bytes / segment.bytes(默认为1GB)。对于段大小(在更干净的部分中)等于1GB,您需要生成具有独特键的大量消息。但是你只生成了4条消息,其中3条消息具有相同的密钥。这就是为什么在包含1111:null消息的段中不删除逻辑删除的原因(段不满足我上面提到的第二点)。

    您可以通过两种方式删除包含4条消息的逻辑删除:

    1. make delete.retention.ms = 0或
    2. make log.segment.bytes / segment.bytes = 50。
    3. 源代码(额外阅读): https://github.com/apache/kafka/blob/trunk/core/src/main/scala/kafka/log/LogCleaner.scala

      try {
            // clean segments into the new destination segment
            for (old <- segments) {
              val retainDeletes = old.lastModified > deleteHorizonMs
              info("Cleaning segment %s in log %s (largest timestamp %s) into %s, %s deletes."
                  .format(old.baseOffset, log.name, new Date(old.largestTimestamp), cleaned.baseOffset, if(retainDeletes) "retaining" else "discarding"))
              cleanInto(log.topicPartition, old, cleaned, map, retainDeletes, log.config.maxMessageSize, stats)
            }
      

答案 2 :(得分:2)

用于删除压缩中的墓碑的算法应该如下。

  1. 当墓碑仍然在日志的脏部分时,它永远不会被删除。
  2. 墓碑位于日志的清理部分后,我们进一步推迟删除墓碑,因为墓碑位于清理过的部分,因此删除了墓碑。
  3. 逻辑删除可能仍然在日志的脏部分,因此不会被清除。触发一些不同密钥的消息应该将墓碑推入日志的已清理部分并删除它们。