Kafka消费者consumer - Go语言中文社区

Kafka消费者consumer


使用消费者组实现消息队列的两种模式

Kafka集群的数据需要被不同类型的消费者使用,而不同类型的消费者处理逻辑不同。Kafka使用消费组的概念,允许一组消费者进程对消费工作进行划分。每个消费者都可以配置一个所属的消费组,并且订阅多个主题。Kafka会发送每条消息给每个消费组中的一个消费者进程( 同一条消息广播给多个消费组,单播给同一组中的消费者)。被订阅主题的所有分区会平均地负载给订阅方,即消费组中的所有消费者。

Kafka采用消费组保证了“一个分区只可被消费组中的一个消费者所消费",这意味着:

(1) 在一个消费组中,一个消费者可以消费多个分区。

(2) 不同的消费者消费的分区一定不会重复,所有消费者一起消费所有的分区。

(3) 在不同消费组中,每个消费组都会消费所有的分区。

(4) 同一个消费组下消费者对分区是互斥的,而不同消费组之间是共享的。

下图给出了多个消费者都在同一个消费组中,或者各向组成一个消费组的不同消费场景,这样Kafka也可以实现传统消息队列的发布——订阅模式和队列模式。

发布-订阅模式:同一条消息会被多个消费组消费,每个消费组只有一个消费者,实现广播
在这里插入图片描述
队列模式:只有一个消费组、多个消费者一条消息只被消费组的一个消费者消费,实现单播
在这里插入图片描述

消费者组再平衡实现故障容错

消费者是客户端的监务处理逻辑程序,因此要考虑消费者的故障容错。一个消费组有多个消费者,因此消费组需要维护所有的消费者。如果一个消费者宕机了,分配给这个消费者的分区需要重新分配给相同组的其他消费者;如果一个消费者加入了同一个组,之前分配给其他消费组的分区需要分配给新加入的消费者。

一旦有消费者加入或退出消费组,导致消费组成员列表发生变化,消费组中所有的消费者就要执行再平衡( rebalance ) 工作。 如果订阅主题的分区有变化,所有的消费者也都要再平衡。如下图所示,在加入一个新的消费者后,需要为所有的消费者重新分配分区,因此所有消费者都会执行再平衡。
在这里插入图片描述

在这里插入图片描述

消费者再平衡前后分配到的分区会完全不同,那么消费者之间如何确保各向消费消息的平滑过渡呢?假设分区P1原先分配给消费者C1 ,再平衡后被分配给消费者C2 。如果再平衡前消费者C1保存了分区P1的消费进度,再平衡后消费者C2 就可以从保存的进度位置继续读取分区P1,保证分区P1不管分配给哪个消费者,消息都不会丢失,实现了消费者的故障容错。

1. 保存消费进度

生产者的提交日志采用递增的偏移量,连同消息内容一起写入本地日志文件。生产者客户端不需要保存偏移量相关的状态,消费者客户端则要保存消费消息的偏移量即消费进度。消费进度表示消费者对一个分区已经消费到了哪里。

由于消费者消费消息的最小单元是分区,因此每个分区都应该记录消费进度,而且消费进度应该面向消费组级别。假设面向的是消费者级别,再平衡前分区P1只记录到消费者C1中,再平衡后分区P1属于消费者C2。但是这样一来,分区P1和消费者C2之前没有记录任何信息,就无法做到无缝迁移。而如果针对消费组,因为消费者C1和消费者C2属于同一个消费组,再平衡前记录分区P1到消费组l ,再平衡后消费者C2可以正常地读取消费组l 的分区P1进度,还是可以准确还原出这个分区在消费组l 中的最新进度的。总结下,虽然分区是以消费者级别被消费的,但分区的消费进度要保存成消费组级别的。

消费者对分区的消费进度通常保存在外部存储系统中,比如ZK 或者Kafka 的内部主题(__consumer_offsets)。
这样分区的不同拥有者总是可以读取同一个存储系统的消费进度,即使消费者成员发生变化,也不会影响消息的消费和处理。如下体所示,消费者消费消息时,需要定时将分区的最新消费进度保存到ZK 中。当发生再平衡时,消费者拥有的新分区消费进度都可以从ZK中读取出来,从而恢复到最近的消费状态。

在这里插入图片描述

由消费者保存消费进度的另一个原因是:消费者消费消息是主动从服务端拉取数据,而不是由服务端向消费者推送数据。如果由服务端推送数据给消费者,消费者只负责接收数据,就不需要保存状态了。但后面这种方法会严重影响服务端的性能,因为要在服务端记录每条消息分配给哪个消费者,还要记录消费者消费到哪里了。

2. 消费者与ZK的关系

消费者除了需要保存消费进度到ZK中,它分配的分区也是从ZK读取的。ZK不仅存储了Kafka的内部元数据,而且记录了消费组的成员列表、分区的消费进度、分区的所有者

消费者要消费哪些分区的消息由消费组来决定,因为消费组管理所有的消费者,所以它需要知道集群中所有可用的分区和所有存活的消费者,才能执行分区分配算法,而这些信息都需要保存到ZK中。每个消费者都要在ZK的消费组节点下注册对应的消费者节点,在分配到不同的分区后,才会开始各自拉取分区的消息。

通常,客户端代码并不直接完成上面那些复杂的操作步骤,而是由服务端暴露出一个API接口,让客户端可以透明地和集群交互。这个API接口实际上属于客户端进程范畴,用来和管理员以及数据存储节点通信。Kafka提供了两种层次的客户端API : 如果消费者不太关心消息偏移量的处理,可以使用高级API ;如果想自定义消费逻辑,可以使用低级API 。

高级API:消费者客户端代码不需要管理偏移量的提交,并且采用了消费组的自动负载均衡功能,确保消费者的增减不会影响消息的消费。高级API提供了从Kafka消费数据的高层抽象。

低级API:通常针对特殊的消费逻辑,比如消费者只想消费某些特定的分区。低级API的客户端代码需要自己实现一些和Kafka服务端相关的底层逻辑,比如选择分区的主副本、处理主副本的故障转移等。
(新版kafka已经取消了高低阶之分)

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/Felix_CB/article/details/85169095
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢