Kafka没有删除带有墓碑的钥匙

tp5buhyn  于 2021-06-07  发布在  Kafka
关注(0)|答案(3)|浏览(348)

我创建了一个具有以下属性的Kafka主题
min.cleanable.dirty.ratio=0.01,delete.retention.ms=100,segment.ms=100,cleanup.policy=compact
假设我按1111:1、1111:2、1111:null、2222:1的顺序插入k-v对,现在除了最后一条消息外,日志压缩在其余消息上运行,并清除前两条消息,但保留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
hof1towb

hof1towb1#

墓碑记录被设计保存得更长。原因是,经纪人不跟踪消费者。假设消费者在读取第一条记录后离线一段时间。当消费者情绪低落时,原木的压缩就开始了。如果日志压缩将删除tombstone记录,那么消费者将永远不会知道该记录已被删除的事实。如果使用者实现了一个缓存,那么记录可能永远不会被删除。因此,墓碑被保留更长的时间,以允许离线消费者接收所有墓碑进行本地清理。
墓碑只有在 delete.retention.ms (默认值为1天)。注意:这是一个主题级配置,没有代理级配置。因此,如果要更改配置,则需要设置每个主题的配置。

vuv7lop3

vuv7lop32#

本主题分为两部分:
1) 清洁部分:用Kafka清洁剂至少清洁一次的Kafka原木部分。
2) 脏的部分:Kafka原木的一部分直到现在还没有被Kafka清洁剂清洁过。Kafka保持肮脏的补偿。偏移量>=脏偏移量的所有邮件都属于脏部分。
注意:kafka cleaner会清理所有段(不管段是否在已清理/已脏部分),并在每次脏比率达到min.cleanable.dirty.ratio时重新复制它们。
按段删除墓碑。如果段满足以下条件,则删除段中的墓碑:
段应在原木的清洁部分。
段的上次修改时间应<=(包含偏移量为(脏偏移量-1)的消息的段的上次修改时间)-delete.retention.ms。
很难详细说明第二点,但简单来说,第二点意味着=>段大小应等于log.segment.bytes/segment.bytes(默认为1gb)。为了使段大小(在更干净的部分中)等于1gb,您需要生成大量具有不同密钥的消息。但您只生成了4条消息,其中3条消息具有相同的密钥。这就是为什么在包含1111:null消息的段中不会删除墓碑(该段不满足上面提到的第二点)。
您有两个选项可以删除包含4条消息的墓碑:
使delete.retention.ms=0或
使log.segment.bytes/segment.bytes=50。
源代码(额外阅读):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)
      }
oalqel3c

oalqel3c3#

在压缩文件中删除墓碑的算法应该如下所示。
墓碑永远不会删除时,它仍然在肮脏的部分日志。
在tombstone位于日志的已清理部分之后,我们通过delete.retention.ms进一步延迟删除tombstone,因为tombstone位于已清理部分的时间。
墓碑可能仍在原木的脏部分,因此没有被清除。触发更多不同密钥的消息应该会将逻辑删除消息推入日志的清理部分并删除它们。

相关问题