位移主题:Kafka 的消费者组是怎么保存消费位移的?

1,295 阅读3分钟

这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

相关:Kafka 中的消费者组

消费者位移

前一篇介绍了 Kafka 的消费者组,在消费者组中,每一个消费者实例会被分配到若干个主题分区,负责消费这些分区的消息。在消费的过程中,需要记录下每个分区中的消息「目前消费到哪一个了」,也就是 Kafka 中的消费者位移。这些位移信息都保存在什么地方呢?

消费者位移的存储

在最初的版本中,这些信息都被存储在 ZooKeeper 中,当提交消费者位移的时候(无论是手动还是自动提交),这些信息会被提交到 ZooKeeper 中保存,如果消费者重新启动了,它会自动从 ZooKeeper 中读取已保存的位移信息,这样就知道了上次消费到了什么位置。

但是,消费者每次消费成功一个消息的时候,都会提交位移,而 ZooKeeper 并不适合这种高频的写操作。于是,在后来的版本中,Kafka 更新了位移的管理机制。Kafka 将位移信息作为一条一条普通的 Kafka 消息,保存在一个特定的 Topic 中,这个 Topic 的名字叫 __consumer_offsets,也可以叫做位移主题,这样高频读写就不是什么问题了。

要注意的是,虽然这个 Topic 相较于其他的 Topic 并没有什么特殊之处,但是强烈建议不要操作这个 Topic,老老实实使用 Kafka 的 API 提交位移。

这个主题的创建时机是第一个消费者程序启动的时候,Kafka 会自动创建这个主题,默认情况下,这个主题是一个 50 分区 3 副本的主题,你可以通过 Broker 端的参数 offsets.topic.num.partitionsoffsets.topic.replication.factor 参数来修改这两个默认值。或者,也可以在第一个消费者程序启动之前,使用 Kafka 提供的 API 来手动创建这个主题,并指定分区数和副本数。

位移主题的内容

在位移主题中,消息的格式是 Kafka 定义的,因此,这也是强烈建议不要手动操作这个主题或者向其中发送信息的原因,如果你发送了不符合 Kafka 规定格式的信息,那么 Kafka 就无法解析它,造成的后果就是 Broker 崩溃。

这位移主题中的消息,可以简单地理解为「某个消费者组在某个主题的某个分区的消费位移是多少」,也可以理解为一个键值对,其中的 Key 是 Group ID + Topic + Partition,Value 就是位移,其中的细节这里不多做介绍。

Compact 压实策略

你可能会考虑到一个问题,一个消费者组在一个主题一个分区的位移数据,会随着消费不断地发生变化,这时就会有保存位移的消息不断地被发送到位移主题中,但其实,同一个消费者组在同一个主题同一个分区的位移,只保留最新的一条就可以了,也就是说,只保留最新的结果就可以了,没必要保存它不断变化的过程,这样可以节省大量的存储空间。

Kafka 就是这么做的,它通过 Compact 策略,对于同一个 Key 的消息,只保留最新的一条。(如果你了解 Redis,这与 Redis 的 AOF 重写机制很相似)。

image.png

这个工作是由一个专门的后台线程 Log Cleaner 来完成的,它会定期地巡检待 Compact 的主题,看看是否存在满足条件的可删除数据。