RocketMQ 的重平衡大致实现方式为:在消费者端用一个固定的分配策略将所有的消费队列分配给所有的消费者。通过将每个消费者的分配策略设置成一致,并且将消费者和消费队列排序的方法,保证每个消费者的分配的结果幂等。
2.1 重平衡的触发
RocketMQ 的重平衡在消费端完成。唯一的触发点是一个重平衡线程,触发方式分主动触发和定时触发。
-
主动触发:消费者数量发生变化
-
推模式消费者启动或恢复时,唤醒本地的重平衡线程,立即重平衡。在这之前还上报心跳让 Broker 感知到新消费者启动,发送请求让所有消费者重平衡。 -
消费者关机时,向 Broker 发请求解除注册。Broker 收到请求后发送请求让其他消费者重平衡。
-
主动触发模式可以通过以下配置来关闭,当消费者数量很多,或者频繁上下线时,为了防止频繁进行重平衡,建议关闭主动触发。 -
Broker 级别配置: notifyConsumerIdsChangedEnable
(broker.conf) -
消费组级别配置: notifyConsumerIdsChangedEnable
(通过updateSubGroup
命令设置) -
只要有一个为 false,就不会进行对应消费组的重平衡主动触发。
-
-
-
定时触发:重平衡线程每 20s 触发一次重平衡。
2.2 重平衡类设计
重平衡主要涉及两个类:重平衡实现 RebalanceImpl
和重平衡线程 RebalanceService
-
重平衡线程:客户端实例持有,每个客户端进程一般只有一个,负责定时或者立即触发重平衡。但它只负责触发,重平衡的实际逻辑在实现类中。 -
重平衡实现: -
RebalanceImpl
中保存了消费者负载的消息队列、重分配策略,并实现了重分配的方法(调用重平衡策略)。 -
每个消费者持有一个重平衡实现,根据推和拉模式的不同,分别在 RebalanceImpl
的基础上新实现了推模式和拉模式的重平衡实现。
-
2.3 重平衡流程
消费者按 Topic 维度进行重平衡。
-
从本地缓存中获取 Topic 的所有 Queue -
向 Broker 获取所有消费者 -
按预设的策略将队列分配给消费者 -
判断自己分配到的队列是否变化 -
如果变化则丢弃老队列,开始拉取新队列,并将订阅关系上报到 Broker
-
RocketMQ 的重平衡流程在消费者端完成,但是由 Broker 端发送信号给所有消费者触发。