1 负载均衡实现组件分析
1.1 负载均衡整体概述
-
概述
所谓的负载均衡指的就是,在集群消费模式下,一个消费组里面有多个消费者订阅了一个主题,此主题有多个消息队列(MessageQueue
),负载均衡组件就将这些消息队列平均分给消费组里面的消费者。 -
使用注意点
同一个消费组内的消费者要保持一样主题订阅,否则会导致某些消费队列没有消费者进行消费。 -
组件分析(核心类和策略类)
负载均衡只对集群消费模式的消费者有效,对广播模式的消费者无效的。RocketMQ
的负载均衡是在消费者客户端完成的。
首先抛开其他复杂的关系调用,逻辑,单纯的从负载均衡实现组件上来分析。负载均衡的组件中是RebalanceImpl
这个抽象类,它的实现者有RebalancePushImpl
、RebalanceLitePullImpl
、RebalancePullImpl
分别供几个消费者客户端使用。下图是类结构图。
抽象类中有一个重要的方法doRebalance()
,这个方法是对外使用的。即使用的方式就是创建一个负载均衡实现类的实例,然后调用它的doRebalance()方法即可进行。
1.2 一次负载均衡的流程分析
干的核心事情:
-
将主题的消息队列应用分配策略分配到消费组里面的消费者
-
丢弃删减的消息队列对应的ProcessQueue,创建新增的消息队列的PullRequest和ProcessQueue。这些动作与消费者拉取消息消费相关。
主要流程说明:
-
1 从
ConcurrentMap<String/*主题*/, Set<MessageQueue> /*主题的消息队列*/> topicSubscribeInfoTable
这个map中获取主题对应的MessageQueue
集合,这个map会被一个定时任务(定时的从NameServer获取已订阅主题的路由信息)进行更新;主题的消息队列集合 -
2 获取该消费者所属消费者组下的所有消费者集合;消费者集合
-
3 将消息队列集合和消费者集合按照某个分配策略进行分配;
-
4 分配策略完成分配,当前消费者获得新的消费队列集合或者删减了某些消息队列,接下来将新的消费队列和旧的进行对比
-
5 如果消费者分配到了一个之前没有的mq,那么将会创建一个PullRequest给PullMessageService实现对消息的拉取,如果之前有但是现在没有的那么将会调用里面的ProcessQueue的droped方法来销毁,即不再拉取消息。其中创建新的PullRequest将会计算一次消息拉取偏移量
this.computePullFromWhere(mq);
public void doRebalance(final boolean isOrder) {
// 获取订阅数据
Map<String, SubscriptionData> subTable = this.getSubscriptionInner();
// 遍历订阅数据
for (final Map.Entry<String, SubscriptionData> entry : subTable.entrySet()) {
// 获取主题
final String topic = entry.getKey();
// 根据主题进行负载均衡
this.rebalanceByTopic(topic, isOrder);
}
this.truncateMessageQueueNotMyTopic();
}
private void rebalanceByTopic(final String topic, final boolean isOrder)