前言
消息的清理是 MQ 中间件的基本能力,可以避免 MQ 的存储占用空间无序增长。与其他消息产品不同,Apache Kafka(以下简称 Kafka) 中 topic 上的消息被消费后不会被马上清除,而是由 topic 级别的清理策略来控制。本文将简要介绍 Kafka 中的两种消息清理策略:deletion 和 compaction,探讨他们的应用场景、配置参数以及一些技术细节。
AutoMQ[1] 是与 Apache Kafka 100% 兼容的新一代云原生 Kafka,对 Kafkfa 的存储层进行了重新设计和实现,使得其可以构建在像S3这样的对象存储之上。 得益于 AutoMQ 对 Apache Kafka 的完全兼容,本文中提到的原理和参数对于 AutoMQ 也同样适用。
名词定义
-
消息:Kafka 官方一般称为 event 或 record。一个 event 包含一个 key(可选)和一个 value(消息本体);
-
消息 batch:Kafka 会将多个消息聚合为一个 batch。具体来说,client 以 batch 形式向服务端生产或消费消息,服务端也按照 batch 进行消息的存储;
-
topic partition: topic 的一个分区。Kafka 中一个 topic 会被划分为多个 topic partition,以支持消费端和服务端的负载均衡;
-
segment:Kafka 中消息在存储介质上的基本单位。一个 topic partition 会被划分为多个 segment。它也是消息清理的基本单位;
Deletion or Compaction
我们可以在 Kafka 中为 topic 配置“cleanup.policy”参数,以指定它的清理策略。可选项包括:
-
delete:默认策略,当 segment 的大小或者时间达到阈值后直接删除;
-
compact:基于 key 的压缩策略,绑定同一个 key 的多个消息将仅保留最新的那个消息,其他消息将被删除。Kafka 的内部 topic “__consumer_offsets” 就是 compact 策略。
-
delete + compact:混合策略,老的 segment 会因为大小或时间被删除,同时 topic partition 也会被 compact;
一般来说,如果你的业务关注的是 key 的终态 value(也就是 KV 之类的场景),例如记录用户每日的行走步数,或者账户的余额,那么 compact 比较适合[2]。此外,compact 策略下,业务的 key 最好是可枚举的少数值。key 取值过于分散将会导致 compaction 效果大打折扣,这种场景可以考虑采用 delete + compact 的策略。如果没有明显的 KV 特征,一般采用 delete 策略即可。
注:Kafka 支持修改 topic 的清理策略,无需重启。
清理涉及的线程
Kafka 中以下线程会执行清理逻辑:
-
Scheduler 线程:执行 “kafka-log-retention” 任务,定时检查纯 delete