文章内容收录到个人网站,方便阅读:hardyfish.top/
在 RocketMQ 中,消息队列(Queue)与消费者(Consumer)之间的对应关系由 消费者组 (Consumer Group) 和 负载均衡机制(Load Balancing) 决定。
以下是具体的计算方式及原理整理。
1. 核心概念
(1) 消息队列(Queue)
- 每个主题(Topic)包含多个队列(Queue),队列是消息存储的最小单元。
- 队列用于支持并发处理和消息分片,生产者会将消息发送到某个队列,消费者从队列中拉取消息。
(2) 消费者组(Consumer Group)
- 多个消费者组成一个消费者组,消费者组内的消费者共同消费主题下的所有队列。
- 同一消费者组中的消费者对队列采用负载均衡的方式分配。
- 不同消费者组之间独立消费,互不干扰。
(3) 消费模式
-
集群消费(Clustering Mode) :
- 队列由消费者组内的消费者共同消费,队列通过负载均衡分配。
-
广播消费(Broadcasting Mode) :
- 每个消费者消费主题下的所有队列,不涉及队列分配。
2. 队列与消费者的对应关系
RocketMQ 在 集群消费模式 下,使用 负载均衡机制 分配队列与消费者的关系。
具体过程如下:
(1) 消费者注册
- 消费者启动时,会向 Broker 注册自己,表明所属的消费者组。
- Broker 维护一个消费者组内所有活跃消费者的列表。
(2) 消费者排序
-
Broker 根据消费者的 客户端 ID 对消费者进行字典序排序。
- 客户端 ID 的格式通常是:
IP地址:进程号
。 - 排序后的消费者依次分配序号,即
consumerIndex
。
- 客户端 ID 的格式通常是:
(3) 负载均衡算法
- 核心原则:将主题下的所有队列,按照消费者组内的消费者数量,进行平均分配。
- 默认算法:
- 使用
AllocateMessageQueueAveragely
策略,每个消费者分配连续的一组队列。 - 分配公式:
Java
queueIndex = (queueSize / consumerSize) * consumerIndex
-
queueIndex = (queueSize / consumerSize) * consumerIndex
其中:queueSize
:主题的队列总数。consumerSize
:消费者组内的活跃消费者数量。consumerIndex
:当前消费者在排序后的序号。
3. 示例
假设某主题有 6 个队列(Q0-Q5),消费者组 ConsumerGroupA
中有 3 个消费者(C1、C2、C3),消费者的客户端 ID 和队列分配如下:
(1) 消费者排序
消费者的客户端 ID:
- C1:
192.168.1.10:12345
- C2:
192.168.1.11:12346
- C3:
192.168.1.9:12347
排序结果(按字典序):
- C3:
consumerIndex = 0
- C1:
consumerIndex = 1
- C2:
consumerIndex = 2
(2) 队列分配
队列通过负载均衡算法分配:
- C3:Q0, Q1
- C1:Q2, Q3
- C2:Q4, Q5
4. 动态调整机制
RocketMQ 会根据消费者组的活跃消费者数量动态调整队列分配关系:
-
消费者增加:
- 新消费者加入后,队列会重新分配,所有消费者的序号和分配关系都会更新。
-
消费者退出:
- 退出的消费者释放的队列会被重新分配给其他消费者。
-
心跳检测:
- Broker 通过定期心跳检测确保消费者状态的实时更新。
5. 特殊分配策略
(1) AllocateMessageQueueAveragelyByCircle
-
轮询分配:将队列按轮询方式分配给消费者。
-
示例:
- C1:Q0, Q3
- C2:Q1, Q4
- C3:Q2, Q5
(2) 自定义分配
- RocketMQ 提供接口
AllocateMessageQueueStrategy
,用户可以自定义队列分配逻辑,以满足特殊业务需求。
6. 广播模式
在广播模式下,每个消费者都会消费主题下的所有队列,不涉及队列分配。
适合需要消息被多个消费者同时处理的场景。
总结
RocketMQ 中队列与消费者的对应关系通过 消费者组 和 负载均衡机制 确定:
- 消费者排序 :通过客户端 ID 排序确定
consumerIndex
。 - 队列分配:按照默认的平均分配算法,将队列分配给消费者。
- 动态调整:消费者组的队列分配会根据消费者的增减动态更新。
- 支持多种分配策略和自定义分配,满足不同的业务需求。