本文深入的分析了RocketMQ的Rebalance机制,主要包括以下内容:
Rebalance必要的元数据信息的维护
Broker协调通知机制;
消费者/启动/运行时/停止时Rebalance触发时机
文章篇幅较长,感兴趣的用户可以先收藏,再阅读。
Rebalance机制本意是为了提升消息的并行处理能力。例如,一个Topic下5个队列,在只有1个消费者的情况下,那么这个消费者将负责处理这5个队列的消息。如果此时我们增加一个消费者,那么可以给其中一个消费者分配2个队列,给另一个分配3个队列,从而提升消息的并行处理能力。如下图:
但是Rebalance机制也存在明显的限制与危害。
Rebalance限制:由于一个队列最多分配给一个消费者,因此当某个消费者组下的消费者实例数量大于队列的数量时,多余的消费者实例将分配不到任何队列。
Rebalance危害: 除了以上限制,更加严重的是,在发生Rebalance时,存在着一些危害,如下所述:
消费暂停:考虑在只有Consumer 1的情况下,其负责消费所有5个队列;在新增Consumer 2,触发Rebalance时,需要分配2个队列给其消费。那么Consumer 1就需要停止这2个队列的消费,等到这两个队列分配给Consumer 2后,这两个队列才能继续被消费。
重复消费:Consumer 2 在消费分配给自己的2个队列时,必须接着从Consumer 1之前已经消费到的offset继续开始消费。然而默认情况下,offset是异步提交的,如consumer 1当前消费到offset为10,但是异步提交给broker的offset为8;那么如果consumer 2从8的offset开始消费,那么就会有2条消息重复。也就是说,Consumer 2
并不会等待Consumer1提交完offset后,再进行Rebalance,因此提交间隔越长,可能造成的重复消费就越多。
消费突刺:由于rebalance可能导致重复消费,如果需要重复消费的消息过多;或者因为rebalance暂停时间过长,导致积压了部分消息。那么都有可能导致在rebalance结束之后瞬间可能需要消费很多消息。
基于Rebalance可能会给业务造成的负面影响,我们有必要对其内部原理进行深入剖析,以便于问题排查。我们将从Broker端和Consumer端两个角度来进行说明。Broker端主要负责Rebalance元数据维护,以及通知机制,在整个消费者组Rebalance过程中扮演协调者的作用;而Consumer端分析,主要聚焦于单个Consumer的Rebalance流程。
从本质上来说,触发Rebalance的根本因素无非是两个:1 ) 订阅Topic的队列数量变化 2)消费者组信息变化。导致二者发生变化的典型场景如下所示:
在这里,笔者将队列信息和消费者组信息称之为Rebalance元数据,Broker负责维护这些元数据,并在二者信息发生变化时,以某种通知机制告诉消费者组下所有实例,需要进行Rebalance。从这个角度来说,Broker在Rebalance过程中,是一个协调者的角色。
在Broker内部,通过元数据管理器维护了Rebalance元数据信息,如下图所示:
这些管理器,内部实现都是一个Map。其中:
对于其他分配策略,感兴趣的读者可以自行阅读源码,在实际开发中使用的很少。
特别的,mqadmin工具提供了一个allocateMQ子命令,通过其我们可以预览某个Topic在多个消费者分区是如何分配的,使用方式如下:
消费者计算出分配给自己的队列结果后,需要与之前进行比较,判断添加了新的队列,或者移除了之前分配的队列,也可能没有变化。
对于新增的队列,需要先计算从哪个位置开始消费,接着从这个位置开始拉取消息进行消费;
对于移除的队列,要移除缓存的消息,并停止拉取消息,并持久化offset。
处理完队列变更后,会调用messageQueueChanged方法进行最后一步处理。
对于push和pull的处理逻辑不同。对于push模式主要是进行一些流控参数的更新。
免费学习视频欢迎关注云图智联: