想必你已经了解RocketMQ的设计哲学是,同一时刻同一个Queue只能被一个Consumer持有,
但同一个Consumer可以同时消费多个队列,为了订阅、消费模型的高效,Rocket总是希望将Queue分配的足够均匀,
日常使用时,Consumer的上下线,Queue的动态扩缩容,都可能会破坏分配均衡性,
故而Rocket提供了一套完整的Rebalance机制针对上述状况。
触发条件
总结下来Rebalance一共三个触发条件,两个主动,一个被动。满足任意一个都会触发
1.Consumer启动之时执行start方法主动执行负载均衡逻辑;
2.定时任务触发;
3.Broker下发通知告知Client需要进行负载均衡;
今天重新翻阅代码的时候发现
很巧合三个触发条件或多或少跟DefaultMQPushConsumerImpl.start()都有关系;
DefaultMQPushConsumerImpl.start()
DefaultMQPushConsumerImpl创建实例时,会初始化rebalanceImpl成员变量 private final RebalanceImpl rebalanceImpl = new RebalancePushImpl(this); 此时此刻这个rebalanceImpl对象没有一点作用,因为ta的关键成员属性尚且为null,下文中的start肩负起了赋值重任。
下面是摘录start()主要代码:
public synchronized void start() throws MQClientException {
switch (this.serviceState) {
case CREATE_JUST:
/* 检查配置 */
this.checkConfig();
/* 构建 Topic 订阅信息——SubscriptionData,并添加至 RebalanceImpl 的订阅信息中 */
this.copySubscription();
/* 初始化 MQClientInstance */
this.mQClientFactory = MQClientManager.getInstance()
.getOrCreateMQClientInstance(this.defaultMQPushConsumer, this.rpcHook);
/**
* 丰富 rebalanceImpl 对象属性,注意到了吗之前初始化的对象充血了
* 之前产生的 rebalanceImpl 对象直到此刻才算真正意义上的初始化完成
* rebalanceImpl就是负载均衡的相关实现
*/
this.rebalanceImpl.setConsumerGroup(this.defaultMQPushConsumer.getConsumerGroup());
this.rebalanceImpl.setMessageModel(this.defaultMQPushConsumer.getMessageModel());
this.rebalanceImpl.setAllocateMessageQueueStrategy(this.defaultMQPushConsumer.getAllocateMessageQueueStrategy());
this.rebalanceImpl.setmQClientFactory(this.mQClientFactory);
/**
* 向 MQClientInstance 注册消费者,并启动 MQClientInstance
* 一个 JVM 中的所有消费者、生产者持有同一个 MQClientInstance,MQClientInstance 只会启动一次
*/
boolean registerOK = mQClientFactory.registerConsumer(this.defaultMQPushConsumer.getConsumerGroup(), this);
break;
case
...;
default:
break;
}
/* Consumer