When multiple consumers in a consumer group pull messages from a topic, ApsaraMQ for RocketMQ distributes those messages across consumers using a load balancing policy. This improves throughput and simplifies horizontal scaling.
Choose a load balancing policy
ApsaraMQ for RocketMQ provides two load balancing policies. Which one applies depends on the consumer type and broker version.
| Policy | Default for | Granularity | Best for |
|---|---|---|---|
| Message-based | Push Consumer, Simple Consumer (broker 5.x) | Individual messages | Event-driven workloads where each message is processed independently |
| Queue-based | Pull Consumer (broker 3.x/4.x/5.x) | Entire queues | Stream processing and batch aggregation workloads |
Tip: If your consumers process messages one at a time, message-based load balancing gives you more even distribution and simpler operations. If your consumers aggregate or batch-process messages from a single source, use queue-based load balancing.
Background
Understanding these policies helps you plan for:
Disaster recovery -- how messages are retried and how failover works when local nodes fail.
Message ordering -- how ApsaraMQ for RocketMQ maintains strict first-in-first-out (FIFO) order within a message group.
Horizontal scaling -- how to plan for traffic migration and horizontal scaling when adding or removing consumers.
Broadcast consumption vs. cluster consumption
ApsaraMQ for RocketMQ supports two consumption modes. Load balancing applies only to cluster consumption.
| Mode | Consumers per group | Message delivery | Use case | Load balancing |
|---|---|---|---|---|
| Broadcast | One per group | Every group receives all messages | Gateway push, configuration push | Not applicable |
| Cluster | Multiple per group | Each message goes to one consumer | Microservice decoupling, horizontal scaling | Message-based or queue-based |

Broadcast consumption (left side of diagram): Each consumer group has one consumer that receives all messages. Different consumer groups independently receive the full message stream.
Cluster consumption (right side of diagram): A consumer group has multiple consumers, and messages are distributed among them. Only one consumer in the group processes each message.
Message-based load balancing
How it works
The broker distributes individual messages from a topic evenly across all consumers in a consumer group, regardless of which queue the messages belong to. Multiple consumers can process messages from the same queue concurrently.

In this example, Consumer Group A has three consumers: A1, A2, and A3. All three consume messages from Queue1. The broker assigns each message to one consumer at a time.
When a consumer receives a message, the broker locks that message so it becomes invisible to other consumers. The message stays locked until the consumer acknowledges it or the lock times out. This prevents duplicate processing under normal conditions.
Messages are distributed on demand rather than pre-assigned. You cannot control which specific consumer receives a given message.
Ordered message handling
For ordered messages, ApsaraMQ for RocketMQ guarantees that messages within the same message group are processed in the exact order they were stored on the broker.

Consider four ordered messages (M1 through M4) in message group G1 of Queue1. If consumer A1 is processing M1 and M2, consumer A2 cannot start processing M3 or M4 until A1 has submitted the consumption status for M1 and M2. The broker enforces strict sequential locking to maintain order.
Advantages over queue-based load balancing
| Advantage | How it works | Why it matters |
|---|---|---|
| Even distribution | Messages are allocated on demand, so all consumers stay busy. | With queue-based balancing, mismatched queue and consumer counts can leave some consumers idle. |
| Tolerant of unequal capacity | Slower consumers receive fewer messages automatically. | With queue-based balancing, differences in network conditions or hardware specifications can cause a slow consumer assigned a busy queue to accumulate a backlog while other consumers sit idle. |
| Simpler capacity planning | No need to match the number of queues to the number of consumers. | Add or remove consumers freely without adjusting queue counts. |
When to use
Message-based load balancing is suitable for most online event processing workloads where each message is handled independently -- for example, order processing, notification dispatch, and real-time event handling.
For stream processing or aggregation workloads that require batching messages from the same queue, use queue-based load balancing instead.
Scope
Message-based load balancing is the only policy available for Push Consumer and Simple Consumer types on broker version 5.x. It is enabled by default and requires no additional configuration.
Example
Push Consumer and Simple Consumer types use message-based load balancing automatically. The following Java examples show both consumer types processing messages without any load balancing configuration.
Push Consumer with a message listener:
// Push Consumer: implement a message listener to process messages.
// Load balancing is handled automatically by the broker.
MessageListener messageListener = new MessageListener() {
@Override
public ConsumeResult consume(MessageView messageView) {
System.out.println(messageView);
// Return the consumption result.
return ConsumeResult.SUCCESS;
}
};Simple Consumer with manual acknowledgment:
// Simple Consumer: pull messages, process them, and acknowledge each one.
// Load balancing is handled automatically by the broker.
try {
List<MessageView> messageViewList = simpleConsumer.receive(10, Duration.ofSeconds(30));
messageViewList.forEach(messageView -> {
System.out.println(messageView);
try {
// Acknowledge the message after processing.
simpleConsumer.ack(messageView);
} catch (ClientException e) {
e.printStackTrace();
}
});
} catch (ClientException e) {
// If the pull fails due to throttling or other issues, retry the request.
e.printStackTrace();
}Queue-based load balancing
How it works
The broker assigns each queue in a topic to exactly one consumer in the consumer group. Each consumer then processes all messages from its assigned queues.

In this example, a topic has three queues (Queue1, Queue2, Queue3) and the consumer group has two consumers. Because each queue is assigned to one consumer, consumer A2 gets two queues while A1 gets one. If there are fewer queues than consumers, some consumers receive no queues and remain idle.
Each consumer follows this processing sequence: pull messages from the assigned queue, submit the consumption offset, and persist the offset. Because the consumption status is not returned to the queue when a consumer pulls messages, each queue must be exclusively assigned to a single consumer to prevent duplicate processing.
Queue-based load balancing is designed so that each queue is processed by one consumer. However, the implementation depends on the information negotiation mechanism between the consumer and the broker. ApsaraMQ for RocketMQ does not guarantee that messages in a queue are processed by only one consumer. When consumer or queue counts change, temporary inconsistencies in queue assignment can occur, and a small number of messages may be processed more than once. Always implement idempotent message handling.
Advantages over message-based load balancing
| Advantage | How it works | Why it matters |
|---|---|---|
| Queue affinity | All messages from a queue go to the same consumer. | Enables local aggregation and batch processing within a single consumer. |
| Stream processing support | Consumers maintain stateful processing over a continuous stream from the same queue. | Supports time-windowed computations and running aggregates. |
When to use
Queue-based load balancing is best for stream computing and data aggregation applications that need to batch-process or aggregate messages from the same source. For example, a consumer might collect metrics from a single queue over a time window and compute running averages.
Scope
Queue-based load balancing is the only policy available for consumers on broker versions 3.x and 4.x, including Pull Consumer, default Push Consumer, default Pull Consumer, and Lite Pull Consumer types. On broker version 5.x, Pull Consumer types continue to use queue-based load balancing by default.
No additional configuration is required -- queue-based load balancing is enabled automatically for these consumer types.
Example
For sample code, see LitePullConsumerAssign.java in the Apache RocketMQ code library.
Version compatibility
| Broker version | Available policies | Notes |
|---|---|---|
| 3.x, 4.x | Queue-based only | All consumer types use queue-based load balancing. |
| 5.x | Both message-based and queue-based | Push Consumer and Simple Consumer use message-based by default. Pull Consumer uses queue-based by default. |
The message-based load balancing policy was introduced in broker version 5.0. If you are running broker version 5.x, the active policy depends on the client version and consumer type.
Usage notes
Implement idempotent message handling
Both load balancing policies trigger temporary rebalancing when consumers are added, removed, or when the broker scales. During rebalancing, a small number of messages may be delivered more than once. To handle this, implement deduplication to ensure idempotence for your message consumption logic.