消费者组 Consumer Group 和 重平衡 Rebalance

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/yujianping_123/article/details/97132000

kafka设计了consumer group: 具有可扩展性和容错性的consumer机制,consumer group有3个特性:

1. Consumer Group 下可以有一个或多个 Consumer 实例。
2. Consumer Group有唯一标识Group ID,它是一个字符串。
3. Consumer Group 下所有consumer订阅的主题的单个分区,但是只能分配给组内的某一个 Consumer消费。

如果只有1个group,那么就是点对点(消息队列)模型;如果有多个group,那么就实现了发布/订阅模型。

一般情况下,一个Group 下的consumer实例个数 应该等于该group订阅topic的分区总数

那么,每个consumer实例负责哪个或者哪些分区呢?这里提个概念 Rebalance

Rebalance是分配一致性协议,规定了所有的consumer如何达成共识,怎么去分配订阅topic的每个分区。

当group内consumer实例数发生变化、订阅的topic数发生变化、订阅的topic分区数发生变化,都会触发重平衡Rebalance。

心跳线程

每个消费者端都有个心跳线程(heartbeat thread),用来告知Coordinator组件’我还活着‘。

重平衡Rebalance的通知机制是通过心跳线程来完成的。当协调者决定开启新一轮重平衡后,它会将“REBALANCE_IN_PROGRESS”封装进消费者心跳请求的响应中,发还给消费者实例,来通知消费者要进行重平衡过程了。

kafka设计了消费者组状态机来协调完成整个Rebalance过程。

消费者组有5中状态:

Empty,Dead,Preparing Rebalance(加入组),Completing Rebalance(等待leader consumer的分配方案), Stable(完成)

Rebalance的缺点是:

1. 在Rebalance过程中,所有的consumer实例都要停止消费,有点像jvm的垃圾回执机制stop the world。

2. 一旦Rebalance,所有的consumer实例都要重新分配分区,那么实例连接在broker上tcp连接要断开然后重连。

希望社区能参考‘一致性哈希’算法,尽量减少全局的变动。

所以,尽量避免重平衡Rebalance的发生,

比如:

1. Broker端Coordinator组件没有收到group下的某consumer实例的心跳,则认为它挂了,默认是heartbeat.interval.ms = 10s检测一次,可以多设置几轮心跳请求,session.timeout.ms >= n * heartbeat.interval.ms ; n比如是3. 当超过session.timeout.ms时,该consumer实例就被剔除了。如果是consumer主动关闭,则第一时间会Rebalance。

2. 如果Consumer消费端处理业务逻辑的时间过长,或者max.poll.interval.ms设置的太小,或者max.poll.records设置的太大,这3种情况也可能会触发Rebalance。总之,consumer实例poll一次后(poll拉取消息前会自动提交offset到__consumer_offsets中,当时间间隔超过了设置的max.poll.interval.ms值,下一次调用poll方法还迟迟未发生时,consumer group会开启Rebalance,并且把将要提交offset的分区分配给了另一个consumer实例,原consumer实例遗憾的被踢出了。如果是手动提交时(enable.auto.commit = false),当下一次poll时,会触发CommitFailedException异常,说明了本次提交offset失败。悲剧的是,另一个consumer并不知道offset提交失败,从而导致了重复消费问题。

顺便提下位移 Offset。 consumer group怎么管理offset呢,用一组KV对, K是分区,V是消费该分区的offset。

以前,consumer group的位移数据是放在Zookeeper中,后来发现这会降低zookeeper集群的性能。

现在,consumer group将位移数据保存在broker端的内部主题中,

即把位移数据作为普通的kafka消息,提交到位移主题(__consumer_offsets)中,

__consumer_offsets的主要作用就是:保存Kafka消费者的位移信息

设计上,__consumer_offsets的key是: consumer group id + topic + partition

__consumer_offsets是kafka自动创建的,默认分区数是50,副本数是3。

注意:下面说的‘位移’指的是consumer端的位移,记录了consumer要消费的下一条消息的位移。

consumer端默认是自动提交位移,即enable.auto.commit = true, 配合auto.commit.interval.ms定期间隔时间提交位移,缺点是:消费太快时,可能写入的位移前一次是10,该次是15? 如果没有消息可消费时,会定期一直写入10,直到有新消息可消费。

推荐采用手动提交offset,即enable.auto.commit = false。有2种提交机制:consumer.commitSync()(同步,缺点是有阻塞),或者commitAsync()(异步,缺点是出错了不能自动重试),一般是两者结合一起用(如下图)。

代码:

那么随着时间越长,位移主题占用的磁盘空间越大,kafka后台线程Log Cleaner会定期的删除过期数据。

猜你喜欢

转载自blog.csdn.net/yujianping_123/article/details/97132000