ApsaraMQ for RabbitMQ enforces per-instance TPS limits and closes channels that exceed thresholds. This guide covers prevention, monitoring, and error recovery.
How throttling works
ApsaraMQ for RabbitMQ enforces TPS limits at three levels:
-
Instance total TPS -- caps the combined send and receive throughput of the entire instance.
-
Single-node SendMessage TPS -- caps the send throughput on each backend service node within the cluster.
-
Per-API operation TPS -- caps specific operations such as
basicGet,queueDeclare, andexchangeDeclare.
When any limit is exceeded, the broker returns reply-code=530 with reply-text=denied for too many requests and closes the channel that sent the request. The connection remains open.
Prevent throttling
Instance total TPS
Choose the approach that matches your traffic pattern:
| Traffic pattern | Action |
|---|---|
| Testing, short-term, or unpredictable traffic | Use a serverless instance. For subscription instances, enable the elastic TPS feature. |
| Stable, high-volume production traffic | Upgrade the TPS specification to a higher tier. |
Single-node SendMessage TPS
ApsaraMQ for RabbitMQ distributes traffic across multiple backend nodes. If traffic concentrates on one node, the per-node limit triggers even when the instance-level limit has headroom.
To distribute load evenly across nodes:
-
Open at least 10 connections per queue. Each connection may route to a different node, distributing the send workload.
-
For Spring users, set
CachingConnectionFactoryto CONNECTION mode. This creates a new connection per session instead of multiplexing channels on one. Spring integration.
Monitor peak TPS
Monitor peak TPS to detect when traffic nears the throttling threshold:
CloudMonitor (recommended)
-
Granularity: minute-level (1-minute period).
-
Scope: instance-level peak TPS.
-
Cost: free.
-
Shows TPS trends over the past 14 days.
-
Supports alert rules to notify before throttling occurs.
Query the peak TPS of an instance and configure an alert rule by using CloudMonitor.
Instance Details page (recommended)
-
Granularity: second-level peak TPS.
-
Scope: instance-level and per-API-operation peak TPS.
-
Cost: free.
-
Pinpoints short traffic spikes with second-level precision.
-
Supports per-API-operation filtering.
Only the first 10 minutes of results are displayed.
Query the peak TPS of an instance on the Instance Details page.
Simple Log Service
-
Granularity: second-level peak TPS.
-
Scope: instance-level peak TPS.
-
Cost: billed by Simple Log Service (Billable items of pay-by-feature).
-
Supports SLS query statements for advanced analysis.
Requires familiarity with SLS query syntax. Results may be harder to interpret than CloudMonitor or Instance Details.
Query the peak TPS of an instance by using Simple Log Service.
Throttling thresholds
The following tables list throttling limits by instance type and specification.
Instance total TPS
Serverless instances
| Cluster type | Billing model | Throttling threshold |
|---|---|---|
| Shared cluster | Pay-by-provisioned-capacity-and-elastic-traffic / pay-by-messaging-request | Maximum: 50,000 TPS |
| Exclusive cluster | Pay-by-provisioned-capacity-and-elastic-traffic | 2x the peak TPS included in the basic specification |
Subscription instances
| Edition | Elastic TPS | Throttling threshold |
|---|---|---|
| Enterprise Edition | Disabled | 1x the peak TPS included in the basic specification |
| Enterprise Edition | Enabled | 2x the peak TPS included in the basic specification (maximum: 50,000 TPS) |
| Enterprise Platinum Edition | Disabled | 1x the peak TPS included in the basic specification |
| Enterprise Platinum Edition | Enabled | 2x the peak TPS included in the basic specification (maximum: 50,000 TPS) |
| Professional Edition | Disabled | 1x the peak TPS included in the basic specification |
| Professional Edition | Enabled | 1.5x the peak TPS included in the basic specification |
Single-node SendMessage TPS
The broker limits SendMessage TPS on each backend node in the instance.
| Instance type | Throttling threshold |
|---|---|
| Serverless -- shared (by cumulative amount) | 25,000 TPS |
| Serverless -- dedicated (reserved + elastic) | 25,000 TPS |
| Subscription -- Enterprise Edition | None |
| Subscription -- Enterprise Platinum Edition (reserved + elastic) | 25,000 TPS |
| Subscription -- Professional Edition | 25,000 TPS |
Per-API operation limits
These limits apply per instance. Serverless exclusive cluster instances have no per-API throttling.
| Operation | API method | Serverless (shared) | Serverless (exclusive) | Subscription |
|---|---|---|---|---|
| Synchronous message receiving | basicGet |
500 TPS | None | 500 TPS |
| Queue clearance | purgeQueue |
500 TPS | None | 500 TPS |
| Exchange creation | exchangeDeclare |
500 TPS | None | 500 TPS |
| Exchange deletion | exchangeDelete |
500 TPS | None | 500 TPS |
| Queue creation | queueDeclare |
500 TPS | None | 500 TPS |
| Queue deletion | queueDelete |
500 TPS | None | 500 TPS |
| Binding creation | queueBind |
500 TPS | None | 500 TPS |
| Binding deletion | queueUnbind |
500 TPS | None | 500 TPS |
| Message restoration | basicRecover |
500 TPS | None | 500 TPS |
| Message requeuing | basicReject(requeue=true) / basicNack(requeue=true) |
20 TPS | None | 20 TPS |
Handle throttling errors
Error code and message
When throttling is triggered, the broker closes the affected channel and returns:
-
Error code:
reply-code=530 -
Error message:
reply-text=denied for too many requests
The error includes the request ID (ReqId), destination queue (dstQueue), source exchange (srcExchange), and binding key (bindingKey).
Recover from channel closure
Because only the channel is closed, catch AlreadyClosedException and recreate it. The following Java example demonstrates retry-based recovery:
private static final int MAX_RETRIES = 5; // Maximum retry attempts
private static final long WAIT_TIME_MS = 2000; // Wait time between retries in milliseconds
private void doAnythingWithReopenChannels(Connection connection, Channel channel) {
try {
// ......
// Any operation to be performed in the current channel.
// For example, sending or consuming messages.
// ......
} catch (AlreadyClosedException e) {
String message = e.getMessage();
if (isChannelClosed(message)) {
// Channel was closed by the broker. Recreate it.
channel = createChannelWithRetry(connection);
// Continue with other operations after recovery.
// ......
} else {
throw e;
}
}
}
private Channel createChannelWithRetry(Connection connection) {
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
return connection.createChannel();
} catch (Exception e) {
System.err.println("Failed to create channel. Attempt " + attempt + " of " + MAX_RETRIES);
// If channel creation fails (possibly still throttled), wait and retry.
if (attempt < MAX_RETRIES) {
try {
Thread.sleep(WAIT_TIME_MS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // Restore the interrupted state.
}
} else {
throw new RuntimeException("Exceeded maximum retries to create channel", e);
}
}
}
throw new RuntimeException("This line should never be reached");
}
private boolean isChannelClosed(String errorMsg) {
// Check whether the error message contains "channel.close".
// This covers both error code 530 (throttling) and 541 (internal error).
if (errorMsg != null && errorMsg.contains("channel.close")) {
System.out.println("[ChannelClosed] Error details: " + errorMsg);
return true;
}
return false;
}
Key points:
-
The retry uses a fixed 2,000 ms wait. Adjust based on your traffic pattern.
-
The
isChannelClosedmethod checks forchannel.closein the error message, which covers bothreply-code=530(throttling) and other channel closure scenarios. -
After recovery, resume operations on the new channel object.