[干货!!!] Kafka冷门知识——主题删除背后的秘密_java

今天笔者抛开惯有的陈述思路,在本文开篇中先让大家来思考一个问题,这个问题也是来源于一次真实的应用案例,案例内容的具体步骤如下:

  • step 1. 创建一个主题,假设主题名为topic-offset;

  • step 2. 创建生产者往这个主题中写入若干消息,然后关闭生产者;

  • step 3. 创建消费者消费这个主题中的消息,并将消费位移存入__consumer_offsets这个主题中(假设这里消费组的名称groupId="group.offset"),然后关闭消费者;

  • step 4. 删除topic-offset这个主题;

  • step 5. 在step3中提交的消费位移过期时间内(Kafka中默认过期时间是1440mins,即1天)再次创建topic-offset主题,主题的所有属性均和step 1中的相同;

至此,便可以引出了笔者的问题了:如果此时再创建一个消费者,并且这个消费者设置的消费组的名称也为"group.offset",那么这个消费者是从step 3中__consumer_offsets中保存的位置开始消费还是根据消费者自身所设置的“auto.offset.reset”参数来决定开始消费的位置。

[干货!!!] Kafka冷门知识——主题删除背后的秘密_java_02

或许你对这个问题一脸懵逼,笔者先来简单讲一下消费位移的相关知识点:我们知道在旧版的消费者中会将消费位移存储在Zookeeper节点中,显然Zookeeper不适合多写的应用场景。在新版的消费者中将消费位移存储在了Kafka内部的主题__consumer_offsets中。每当消费者有消费位移提交时,会通过OffsetCommitRequest请求将所提交的位移发送给消费者所属消费组对应的组协调器GroupCoordinator中,组协调器GroupCoordinator会将消费位移存入到__consumer_offsets主题中,同时也会在内存中保留一份备份。Kafka重启之后会将__consumer_offsets中所有的消息保存到内存中,即保存到各个GroupCoordinator中来进行维护。

如此看起来__consumer_offsets中的消费位移不会丢失,也就是说在step 5之后再创建一个相同消费组下的消费者时是会获取(OffsetFetchRequest)到之前提交的位移信息的,事实是否真的如此,这里先卖个关子,我们从主题的删除过程来进行切入分析。

就以topic-offset为例,我们可以通过kafka-topics.sh脚本、KafkaAdminClient等工具来删除它,这波操作产生的最直接的结果就是在Kafka对应的Zoopeer中的/admin/delete_topics/路径下创建一个以“topic-offset”命名的实节点。KafkaController会监听/admin/delete_topics/路径下的节点变化,当监听到有节点变化时就会接过前面kafka-topics.sh脚本、KafkaAdminClient等工具的交接棒,负责接下去的具体的删除工作,对于删除“topic-offset”而言,具体的工作有如下:

  1. 删除Zookeeper中的/admin/delete_topics/topic-offset节点、/brokers/topics/topic-offset节点以及/config/topics/topic-offset节点,后两个节点和主题的元数据信息、配置信息有关,所以也要删除掉。

  2. 通知各个broker节点将主题“topic-offset”下的所有日志文件标记删除,具体可以查看Kafka日志删除那部分的细节。

  3. 通知各个broker节点中的GroupCoordinator以删除有关此主题的消费位移信息。
    前两个大家都能猜想的出来,第3个大家未必有所了解。GroupCoordinator会遍历旗下所有的消费组,然后删除有关topic-offset的分区信息,并且通过在__consumer_offsets中设置墓碑消息来删除对应的记录。

下图中__consumer_offsets主题中有关消费位移的消息格式,图中上半部分表示消息的key,里面包含version(版本信息)、group(消费组的名称)、topic(主题名称,这里就是topic-offset)以及partition(分区编号);图中下半部分表示消息的value,对于墓碑消息来说,value设置为null,由于__consumer_offsets的清理策略是compact的,这个墓碑消息最终会被清除掉。

[干货!!!] Kafka冷门知识——主题删除背后的秘密_java_03

分析到这里,我们再来回顾文中开篇的问题,相信到这里答案已经显而易见了,删除了主题之后会顺带着将主题相关的所有消费位移信息全部删除,故在step 5之后的新消费者无迹可寻,只能按照其所配置的auto.offset.reset参数来做具体的earliest或者lateset的重置消费。

本文中涉及到的概念有GroupCoordinator、KafkaController、Kafka日志删除、Kafka协议、GroupMetadata、墓碑消息等,如果你对此一无所知或者一知半解的话,那么说明你对Kafka的认知接近为0,如何排解未知的恐慌?——将进度条拉到最上方,点击关注本微信公众号

同时欢迎加入群聊:消息生态圈。加入我们,更多有意思的话题等你来辩~

本周话题摘要
1.为什么Kafka中的副本只支持主写主读,不支持读写分离?
2.为什么Kafka中的分区数只能增不能减? 
3.Kafka中有几处leader/follower的概念?分别是那几处?它们都各种采取什么样的选举方式?

友情推广潇洒峰的微信公众号:HBase技术社区。新鲜的一手HBase资料等你来拿。

[干货!!!] Kafka冷门知识——主题删除背后的秘密_java_04