kafka消费者

一、消费者组(group)

多个consumer通过设置相同的group.id可以使这多个consumer属于同一个消费者组(group)。这多个consumer订阅同一个topic后,topic中的一个partition只能被group中的一个consumer消费,不允许有同一个group中的两个及以上consumer消费topic中的同一个partition。也就是说一个consumer可以消费topic中的多个partition,topic中的一个partition只能被同一个group中的一个consumer消费。

group可以实现消息的广播(topic下每条消息需要被订阅了该topic的所有consumer消费)和单播(topic下的消息被订阅了该topic的某一个consumer消费)。如果需要消息广播,那么可以将订阅了该topic的消费者分散在不同的group中即可;如果要实现消息的单播,就需要将订阅了该topic的消费者全部放在同一个group中。

当producer向broker中写消息的速度大于consumer读消息的速度时,就会产生消息积压,而broker的容量有限,久而久之就会出现producer写消息失败影响到业务逻辑应用的正常运行。这种情况下我们可以通过在同一个group中扩展consumer的个数来提高消息的消费速度(当topic下partition的个数小于group中consumer的个数时可行,当group中consumer数量大于topic下partition数量时,多余的consumer并不会去消费partition中的消息)。

下面我们通过一个栗子来进一步熟悉一下消费者组:

(1)、假设主题topic1有4个分区partition0、partition1、partition2、partition3,我们创建消费者consumer1,它是消费者组group1中唯一的消费者,我们用它来订阅主题topic1。消费者consumer1将会收到主题topic1中全部分区的消息,如图一所示:

(2)、如果在消费者组group1中新增一个消费者consumer2,那么每个消费者将分别从两个分区接收消息。我们假设consumer1接收partition0和partition1的消息,consumer2接收partition2和partition3的消息,如图二所示:

(3)、如果消费者组group1中有4个消费者,数量与主题topic1的分区数相同,那么每个消费者可以分配一个分区,如图三所示:

(4)、如果再继续向消费者组group1中添加更多的消费者,使消费者数量大于主题的分区数量,那么有一部分消费者就会被闲置,不会接收到消息,如图四所示:

 (5)、如果新增一个消费者组group2并且该组内消费者都订阅了主题topic1,那么这两个消费者组中的消费者会互不干扰,如图五所示:

二、分区再均衡

再均衡是指分区的所属权从同一消费者组内的一个消费者转移到另一个消费者的行为,在再均衡发生期间,消费者组内的消费者是无法读取消息的,当一个分区被重新分配给另一个消费者时,消费者当前的状态也会丢失。比如消费者消费完某个分区中一部分消息,还没来得及提交offset就发生了再均衡,该分区被分配给组内另一个消费者,那么新的消费者会把旧的消费者已经消费但未提交offset的那部分消息又重新消费一次,这样就会产生消息的重复消费。一句话总结,分区归属换人,消费起点不变,只看组维度已提交偏移量,和谁在消费无关。

1、再均衡的触发条件

(1)、消费者组内成员变更

  • 新的消费者加入组(扩容)
  • 消费者退出组(缩容)
  • 消费者崩溃失连(会话超时session.timeout.ms)
  • 消费者处理速度太慢(超过max.poll.interval.ms,被判定死亡)

(2)、topic元数据变更

  • topic分区数量增加
  • 正则表达式订阅到新的topic

(3)、协调器变更

  •  协调器所在broken节点宕机,新协调器接管,可能触发再均衡

2、再均衡的影响

(1)、消费中断:经典协议下全组暂停消费,持续数秒到数分钟

(2)、数据重复:未提交完成就触发再均衡,重复消费

(3)、延迟与堆积:中断期间消息堆积,恢复后消费延迟飙升

3、如何避免因消费者重启而产生的再均衡

(1)、为什么会触发

服务停止->消费者下线,组内消费者数量减少相当于缩容。心跳断了,会话session.timeout.ms超时。协调器判断消费者离开了消费者组,立即出发全组再均衡,重新分配订阅主题下所有分区。重启上线后组内消费者数量增加,相当于扩容,又触发一次再均衡。一次启停,两次再均衡,再均衡期间全组消费停止。

(2)、如何重启不触发均衡

配置关键参数如下:

# 设置静态成员
group.instance.id=consumer-01
# 会话超时时间(毫秒) session.timeout.ms
=30000 # 静态成员离线最大容忍时间,超时依旧会被踢(毫秒)
group.static.membership.timeout.ms=60000

通过group.instance.id将当前消费者设置成静态成员,静态成员在重启时不会退出消费者组,只是短暂离线,恢复后直接拿回原分区,全程不触发再均衡,当然重启时间不能大于group.static.membership.timeout.ms,否则依旧会触发再均衡。注:不能同一组内重复使用同一个group.instance.id。

三、配置参数

1、必要参数

(1)、bootstrap.servers

指定连接kafka集群的地址清单,格式为host:port,多个地址之间用英文逗号隔开。并非需要设置集群中所有broker地址,消费者会从现有的配置中找到全部的kafka集群成员。

(2)、group.id

消费者所属的消费者组的名称,不能为空。

(3)、client.id

消费者的id

(4)、key.deserializer和value.deserializer

消费者从broker端获取的消息都是字节数组,需要反序列化来还原成原有数据。

2、可选参数

(1)、fetch.min.bytes

用来设置从broker中一次拉取的最小数据量,默认是1B。consumer从broker节点拉取数据时,如果给consumer返回的数据量小于该配置值,则consumer需要等待,直到数据量大于该配置值(或者等待时间大于fetch.max.wait.ms)。可以提高该参数值来提升吞吐量,但同时会造成消费端延迟。

(2)、fetch.max.bytes

表示从broker中一次拉取的最大数据量,默认是50MB。如果该配置值比任意一条消息都小时,为了确保消费者能够正常工作,是可以被消费的。

(3)、fetch.max.wait.ms

最大等待时间,默认500ms。当一次拉取的数据量小于fetch.min.bytes时,需要等待,如果等待时间大于该配置值,数据量都没有大于fetch.min.bytes,则消费者会先消费这一批数据。

(4)、max.partition.fetch.bytes

每个分区返回给consumer的最大数据量,默认1MB。与fetch.max.bytes相似,fetch.max.bytes是一次拉取总的数据量最大值。因为一个consumer可以消费多个partition中的消息,所以该参数是限制一次拉取中,每个partition返回的最大数据量,当然该值小于任意一条消息时,也是可以被消费的。

(5)、max.poll.records

一次拉取中消息最大条数,默认500条。当每条消息都比较小时,可以提升该参数来提升消费速度。

(6)、connections.max.idle.ms

空闲连接最大存活时间,默认9分钟。

(7)、exclude.internal.topics

kafka中有两个内部主题(_consumer_offsets和_transaction_state),用来指定内部主题是否可以向消费者公开,默认为true,表示公开。

(8)、receive.buffer.bytes

socket接收消息的缓冲区大小,默认64KB。

(9)、send.buffer.bytes

socket发送消息的缓冲区大小,默认128KB。

(10)、request.timeout.ms

consumer等待请求响应的最大时间,默认30000ms。

(11)、metadata.max.age.ms

元数据过期时间,默认300000ms,即5分钟。该时间范围内没有被更新,则会强制更新,哪怕是元数据没有发生变化。

(12)、reconnect.backoff.ms

尝试重连broker之前的等待时间,避免频繁地连接broker,默认50ms。该机制适用于consumer向broker发送的所有请求(如发送心跳、拉取消息、提交消费偏移量等)。

 

 

posted @ 2021-02-25 18:03  西北-孤狼  阅读(12)  评论(0)    收藏  举报