Kafka日志压缩总是显示相同密钥的最后两个记录

时间:2020-04-25 18:24:53

标签: apache-kafka

找到了两个问题:herehere,但是我还是不太明白。 我仍然有(意外的?)行为。

我尝试使用此配置对紧凑型kafka主题进行日志记录

kafka-topics.sh --bootstrap-server localhost:9092 --create --partitions 1 --replication-factor 1 --topic test1 --config "cleanup.policy=compact" --config "delete.retention.ms=1000" --config "segment.ms=1000" --config "min.cleanable.dirty.ratio=0.01" --config "min.compaction.lag.ms=500"

然后我发送这些消息,每个消息至少间隔1秒

A: 3
A: 4
A: 5
B: 10
B: 20
B: 30
B: 40
A: 6

我期望的是几秒钟后(配置为1000?),当我运行kafka-console-consumer.sh --bootstrap-server localhost:9092 --property print.key=true --topic test1 --from-beginning时,我应该得到

A: 6
B: 40

相反,我得到了:

A: 5
B: 40
A: 6

如果我发布另一条消息B:50并运行该使用者,则会得到:

B: 40
A: 6
B: 50

而不是预期的

A: 6
B: 50
  1. 实际上,如何配置日志压缩?
  2. Kafka documentation开始:日志压缩可确保Kafka始终为单个主题分区的数据日志中的每个消息键至少保留最后一个已知值
    这是否意味着我只能对具有单个分区的主题使用日志压缩?

1 个答案:

答案 0 :(得分:1)

基本上,您已经自己提供了答案。如Kafka文档中所述,“日志压缩可确保Kafka始终为单个主题分区的数据日志中的每个消息键至少保留最后一个已知的值”。因此,不能保证您一键总是有一条消息。

如果我正确地理解了日志压缩,那么这并不意味着您会遇到非常有效的问题。相反,它的目的是最终进入该主题中每个键仅显示一条消息的阶段。

日志压缩是一种提供更细粒度的每个记录保留的机制,而不是一种基于时间的粗粒度保留。这个想法是有选择地删除具有相同主键的最新更新的记录。这样,可以确保日志至少具有每个键的最后状态。

如果计划只保留每个键的最新状态,并以尽可能少地处理旧状态为目标,则紧凑的主题是正确的选择(取决于时间/大小,未压缩的主题将具有什么状态)基于保留)。据我所知,日志压缩的用例是为了保留最新的地址,移动电话号码,数据库中的值等。这些值并非时刻都在变化,通常在您拥有许多键的地方。

从技术角度来看,我猜您遇到了以下情况。

在压缩方面,日志被视为分为两部分

  • 清除:以前已压缩的邮件。本节每个键只包含一个值,这是上一次压缩时的最新值。
  • :上次压缩后写的邮件。

产生消息B: 40(已经产生A: 5之后,日志的clean部分为空,dirty/active部分包含A: 5和{ {1}}。消息B: 40根本不是日志的一部分。产生新消息A: 6将开始压缩日志的脏部分(因为您的比率很低),但排除新消息本身。如前所述,没有什么需要清除的,因此新消息将仅添加到主题中,并且现在位于日志的脏部分中。产生A: 6时,您会观察到同样的情况。

此外,压缩将从不在您的活动细分中发生。因此,即使将B: 50设置为segment.ms,它也不会产生新的段,因为在产生1000 msA: 6之后没有新的数据传入。

要解决您的问题并遵守期望,您需要在产生B: 50C: 1之后再产生一条消息A: 6。这样,清理人员可以再次比较日志的干净部分和脏部分,并删除B: 50A: 5

同时,请查看分段在Kafka的日志目录中的表现。

从我的角度来看,日志压缩的配置非常好!观察预期的行为并不是正确的用例。但是对于生产用例,请注意您当前的配置会尝试非常频繁地开始压缩。根据数据量的不同,这可能会占用大量I / O。将默认比率设置为B: 40并将log.roll.hours通常设置为24小时是有原因的。另外,您通常希望确保消费者有机会在压缩之前读取所有数据。