Kafka 核心技术与实战
客户端实践及原理剖析
16 | 揭开神秘的“位移主题”面纱
什么是位移主题?
__consumer_offsets 在 Kafka 源码中有个更为正式的名字,叫位移主题,即 Offsets Topic。
Consumer 的位移管理机制就是将 Consumer 的位移数据作为一条条普通的 Kafka 消息,提交到 __consumer_offsets 中。可以这么说,__consumer_offsets 的主要作用是保存 Kafka 消费者的位移信息。它要求这个提交过程不仅要实现高持久性,还要支持高频的写操作。显然,Kafka 的主题设计天然就满足这两个条件。
位移主题的 Key 中应该保存 3 部分内容:<Group ID,主题名,分区号 >。
位移主题的消息格式有 3 种消息格式:
- 用于保存位移值、位移提交的一些其他元数据,诸如时间戳和用户自定义的数据等。
- 用于保存 Consumer Group 信息的消息(用来注册 Consumer Group)。
- 用于删除 Group 过期位移甚至是删除 Group 的消息,即 tombstone 消息,即墓碑消息,也称 delete mark,它的主要特点是它的消息体是 null,即空消息体。
一旦某个 Consumer Group 下的所有 Consumer 实例都停止了,而且它们的位移数据都已被删除时,Kafka 会向位移主题的对应分区写入 tombstone 消息,表明要彻底删除这个 Group 的信息。
位移主题是怎么被创建的?
1.当 Kafka 集群中的第一个 Consumer 程序启动时,Kafka 会自动创建位移主题。
位移主题的分区由 Broker 端参数 offsets.topic.num.partitions 设置,默认值是 50,因此 Kafka 会自动创建一个 50 分区的位移主题。
副本数由 Broker 端参数 offsets.topic.replication.factor 设置,它的默认值是 3。
如果位移主题是 Kafka 自动创建的,那么该主题的分区数是 50,副本数是 3。
2.也可以选择手动创建位移主题,具体方法就是,在 Kafka 集群尚未启动任何 Consumer 之前,使用 Kafka API 创建它。手动创建的好处在于,可以创建满足实际场景需要的位移主题。比如很多人说 50 个分区太多了,不想要这么多分区,可以自己创建它,不用理会 offsets.topic.num.partitions 的值。
建议还是让 Kafka 自动创建比较好。 目前 Kafka 源码中有一些地方硬编码了 50 分区数,因此如果自行创建了一个不同于默认分区数的位移主题,可能会碰到各种各样奇怪的问题。
Consumer 是怎么提交位移的呢?
目前 Kafka Consumer 提交位移的方式有两种:自动提交位移和手动提交位移。
Consumer 端有个参数叫 enable.auto.commit,如果值是 true,则 Consumer 在后台默默地定期提交位移,提交间隔由一个专属的参数 auto.commit.interval.ms 来控制。自动提交位移有一个显著的优点,就是省事,不用操心位移提交的事情,就能保证消息消费不会丢失。但这一点同时也是缺点。因为它太省事了,以至于丧失了很大的灵活性和可控性,没法把控 Consumer 端的位移管理。
事实上,很多与 Kafka 集成的大数据框架都是禁用自动提交位移的,如 Spark、Flink 等。这就引出了另一种位移提交方式:手动提交位移,即设置 enable.auto.commit = false。Kafka Consumer API 提供了位移提交的方法,如 consumer.commitSync 等。当调用这些方法时,Kafka 会向位移主题写入相应的消息。
如果选择的是自动提交位移,那么就可能存在一个问题:只要 Consumer 一直启动着,它就会无限期地向位移主题写入消息。
假设 Consumer 当前消费到了某个主题的最新一条消息,位移是 100,之后该主题没有任何新消息产生,故 Consumer 无消息可消费了,所以位移永远保持在 100。由于是自动提交位移,位移主题中会不停地写入位移 =100 的消息。显然 Kafka 只需要保留这类消息中的最新一条就可以了,之前的消息都是可以删除的。这就要求 Kafka 必须要有针对位移主题消息特点的消息删除策略,否则这种消息会越来越多,最终撑爆整个磁盘。
Kafka 是怎么删除位移主题中的过期消息的呢?
Kafka 使用 Compact 策略来删除位移主题中的过期消息,避免该主题无限期膨胀。
Compact 的过程就是扫描日志的所有消息,剔除那些过期的消息,然后把剩下的消息整理在一起。
Kafka 提供了专门的后台线程定期巡检待 Compact 的主题,看看是否存在满足条件的可删除数据。这个后台线程叫 Log Cleaner。很多实际生产环境中都出现过位移主题无限膨胀占用过多磁盘空间的问题,如果出现这个问题,建议去检查一下 Log Cleaner 线程的状态,通常都是这个线程挂掉了导致的。