消费者与消费组
消费者(Consumer)负责订阅Kafka中的主题(Topic),并且从订阅的主题上拉取消息。
消费组(Consumer Group)每个消费者都有一个对应的消费组。当消息发布到主题后,只会被投递给订阅它的每个消费组中的一个消费者。
特性
-
每一个分区只能被一个消费组中的一个消费者所消费。
消费组内的消费者个数变化
消费者与消费组这种模型可以让整体的消费能力具备横向伸缩性,我们可以增加(或减少)消费者的个数来提高(或降低)整体的消费能力。
消费步骤
- 配置消费者客户端参数及创建相应的消费者实例;
- 订阅主题(订阅主题或者直接订阅主题的特定分区);
- 拉取消息并消费;
- 提交消费位移;
- 关闭消费者实例。
到目前为止,可以简单地认为poll()方法只是拉取一下消息而已,但就其内部逻辑而言并不简单,它涉及消费位移、消费者协调器、组协调器、消费者的选举、分区分配的分发、再均衡的逻辑、心跳等内容,在后面的章节中会循序渐进地介绍这些内容。
消息消费
Kafka中的消费是基于拉模式的,Kafka中的消息消费是一个不断轮询的过程。
位移提交
对于Kafka中的分区而言,它的每条消息都有唯一的offset,用来表示消息在分区中对应的位置。对于消费者,也有一个offset,消费者使用offset来表示消费到分区中某个消息所在的位置。
在每次拉取消息时,返回的是还没有被消费过的消息集,要做到这一点,就需要记录上一次消费时的消费位移。并且这个消费位移必须做持久化保存,而不是单单保存在内存中,否则消费者重启之后就无法知晓之前的消费位移。再考虑一种情况,当有新的消费者加入时,那么必然会有再均衡的动作,对于同一分区而言,它可能在再均衡动作之后分配给新的消费者,如果不持久化保存消费位移,那么这个新的消费者也无法知晓之前的消费位移。
这里把将消费位移存储起来(持久化)的动作称为“提交”,消费者在消费完消息之后需要执行消费位移的提交。
当前消费者提交的消费位移并不是 x,而是 x+1。对应于图3-6中的position,它表示下一条需要拉取的消息的位置。
位移提交的具体时机
重复消费:消费完成后,才进行位移提交。消费异常,恢复后会重新拉取。
消息丢失:拉取到消息后立即进行位移提交,消费异常。
自动提交、手动提交
Kafka 中默认的消费位移的提交方式是自动提交,这个由消费者客户端参数enable.auto.commit配置,默认值为 true。当然这个默认的自动提交不是每消费一条消息就提交一次,而是定期提交,这个定期的周期时间由客户端参数auto.commit.interval.ms配置,默认值为5秒,此参数生效的前提是enable.auto.commit参数为true。自动提交是延时提交,会有重复消费和消息丢失问题。
指定位移消费
在 Kafka 中每当消费者查找不到所记录的消费位移时,就会根据消费者客户端参数auto.offset.reset的配置来决定从何处开始进行消费。
这个参数的默认值为“latest”,表示从分区末尾开始消费消息;如果将auto.offset.reset参数配置为“earliest”,那么消费者会从起始处,也就是0开始消费。
再均衡
再均衡是指分区的所属权从一个消费者转移到另一消费者的行为,它为消费组具备高可用性和伸缩性提供保障,使我们可以既方便又安全地删除消费组内的消费者或往消费组内添加消费者。不过在再均衡发生期间,消费组内的消费者是无法读取消息的。也就是说,在再均衡发生期间的这一小段时间内,消费组会变得不可用。另外,当一个分区被重新分配给另一个消费者时,消费者当前的状态也会丢失。比如消费者消费完某个分区中的一部分消息时还没有来得及提交消费位移就发生了再均衡操作,之后这个分区又被分配给了消费组内的另一个消费者,原来被消费完的那部分消息又被重新消费一遍,也就是发生了重复消费。一般情况下,应尽量避免不必要的再均衡的发生。
Question
- 消费者为什么要提交偏移量?
- 提交偏移量可能带来的问题。
参考文档