RabbitMQ Benchmarking
Introduction
When building applications that rely on message brokers like RabbitMQ, understanding performance characteristics is crucial for designing scalable systems. Benchmarking allows you to measure how your RabbitMQ setup performs under various conditions and helps you make informed decisions about configuration, hardware requirements, and architectural choices.
In this guide, we'll explore how to properly benchmark RabbitMQ, interpret the results, and use that knowledge to optimize your messaging infrastructure.
Why Benchmark RabbitMQ?
Before diving into the how-to, let's understand why benchmarking RabbitMQ is important:
- Capacity planning: Determine how many messages your current setup can handle
- Configuration optimization: Find the optimal settings for your workload
- Hardware sizing: Understand resource requirements (CPU, memory, disk, network)
- Architecture validation: Confirm your messaging patterns and topology work as expected
- Bottleneck identification: Discover performance limitations in your system
Key Metrics to Measure
When benchmarking RabbitMQ, focus on these essential metrics:
- Throughput: Messages per second that can be published and consumed
- Latency: Time taken for a message to travel from producer to consumer
- Resource utilization: CPU, memory, disk I/O, and network usage
- Queue depth: How messages accumulate when consumers can't keep up
- Connection scalability: How the system performs with increasing connection counts
Benchmarking Tools
PerfTest
RabbitMQ's official benchmarking tool is PerfTest
(also known as the Java Client benchmarking tool). It's a versatile utility that simulates producers and consumers with various configurations.
Installation
# Clone the repository
git clone https://github.com/rabbitmq/rabbitmq-perf-test.git
# Build with Maven
cd rabbitmq-perf-test
./mvnw clean package
# The tool will be available at target/rabbitmq-perf-test-VERSION-SNAPSHOT.jar
Alternatively, you can download a pre-built binary:
wget https://github.com/rabbitmq/rabbitmq-perf-test/releases/download/v2.16.0/rabbitmq-perf-test-2.16.0-bin.zip
unzip rabbitmq-perf-test-2.16.0-bin.zip
cd rabbitmq-perf-test-2.16.0
Basic Usage
Here's a simple benchmark to test publishing and consuming with default settings:
# Run a simple benchmark with 1 producer and 1 consumer
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost
This command will output metrics such as:
starting consumer #0
starting consumer #1
starting producer #0
time: 1.000s, sent: 22626 msg/s, received: 22553 msg/s
time: 2.000s, sent: 28551 msg/s, received: 28523 msg/s
time: 3.000s, sent: 28758 msg/s, received: 28758 msg/s
time: 4.000s, sent: 28699 msg/s, received: 28699 msg/s
time: 5.000s, sent: 28830 msg/s, received: 28830 msg/s
...
Advanced PerfTest Examples
Testing with multiple producers and consumers:
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 5 \
--consumers 10 \
--queue benchmark-queue \
--time 60 \
--autoack \
--size 4096
This command:
- Uses 5 producers and 10 consumers
- Creates a queue named
benchmark-queue
- Runs for 60 seconds
- Uses automatic acknowledgments
- Sets message size to 4KB
Testing message persistence:
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 3 \
--consumers 3 \
--queue durable-queue \
--time 30 \
--flag persistent \
--queue-args "x-queue-type=classic"
This benchmark tests durable messages with persistent queues to measure disk I/O impact.
Prometheus and Grafana Integration
For visual monitoring during benchmarks, integrate PerfTest with Prometheus and Grafana:
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--metrics-prometheus \
--producers 2 \
--consumers 2 \
--metrics-tags 'deployment=test,environment=development'
Then configure your Prometheus server to scrape metrics from the default endpoint at http://localhost:8080/metrics
.
Building a Complete Benchmark Plan
A thorough RabbitMQ benchmark should test various scenarios relevant to your use case. Here's a structured approach:
1. Baseline Performance Test
Start with a simple configuration to establish a baseline:
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 1 \
--consumers 1 \
--time 60 \
--queue baseline-queue \
--autoack
2. Scaling Producers and Consumers
Test how performance scales with more producers and consumers:
# Test with more producers than consumers
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 10 \
--consumers 2 \
--time 60 \
--queue scaling-test
# Test with more consumers than producers
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 2 \
--consumers 10 \
--time 60 \
--queue scaling-test
3. Message Size Impact
Compare performance with different message sizes:
# Small messages (256 bytes)
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--size 256 \
--time 60 \
--queue message-size-test
# Large messages (1MB)
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--size 1048576 \
--time 60 \
--queue message-size-test
4. Acknowledgment Modes
Test different acknowledgment strategies:
# Auto-acknowledgment (higher throughput, less safety)
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--autoack \
--time 60 \
--queue ack-test
# Manual acknowledgment (lower throughput, more safety)
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--time 60 \
--queue ack-test \
--multi-ack-every 100
5. Queue Types
Compare different queue types:
# Classic queues
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--queue-args "x-queue-type=classic" \
--time 60 \
--queue classic-queue-test
# Quorum queues
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--queue-args "x-queue-type=quorum" \
--time 60 \
--queue quorum-queue-test
# Stream queues (RabbitMQ 3.9+)
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--queue-args "x-queue-type=stream" \
--time 60 \
--queue stream-queue-test
Real-World Benchmark Example
Let's walk through a comprehensive benchmark for a hypothetical e-commerce order processing system:
// Node.js producer code example (for reference)
const amqp = require('amqplib');
async function produceOrders(count) {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
const queue = 'order_processing';
await channel.assertQueue(queue, { durable: true });
console.time('orderProduction');
for (let i = 0; i < count; i++) {
const order = {
orderId: `ORD-${Date.now()}-${i}`,
customerId: `CUST-${Math.floor(Math.random() * 10000)}`,
items: Array.from({ length: Math.floor(Math.random() * 5) + 1 },
(_, i) => ({ productId: `PROD-${i}`, quantity: Math.floor(Math.random() * 3) + 1 })),
timestamp: new Date().toISOString()
};
channel.sendToQueue(queue, Buffer.from(JSON.stringify(order)), { persistent: true });
if (i % 1000 === 0) {
process.stdout.write('.');
}
}
console.timeEnd('orderProduction');
await channel.close();
await connection.close();
}
produceOrders(100000).catch(console.error);
Using PerfTest for benchmarking this scenario:
# Order processing benchmark with realistic message size and persistence
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 5 \
--consumers 10 \
--queue order_processing \
--time 300 \
--size 1024 \
--flag persistent \
--queue-args "x-queue-type=quorum,x-max-length=1000000" \
--body content.json \
--consumer-rate 2000
This benchmark:
- Simulates 5 producer services and 10 consumer services
- Uses a message size of 1KB (typical for JSON orders)
- Enables message persistence for durability
- Uses quorum queues for high availability
- Reads message content from a file (
content.json
) - Limits consumer processing rate to 2000 msg/s to simulate processing time
Performance Analysis and Visualization
Let's visualize our benchmark results with a simple diagram:
Common Bottlenecks and Solutions
Network Limitations
Symptoms:
- Throughput plateaus despite increasing resources
- High network utilization
Solutions:
- Increase network capacity (10Gbps+)
- Use fewer, larger batched messages
- Enable compression for large messages
- Consider co-locating producers/consumers with RabbitMQ
// Node.js example with compression
const payload = JSON.stringify(largeObject);
const compressed = await gzip(payload); // Using a compression library
channel.sendToQueue(queue, Buffer.from(compressed), {
persistent: true,
contentEncoding: 'gzip',
contentType: 'application/json'
});
Disk I/O Bottlenecks
Symptoms:
- Performance drops with persistent messages
- High disk wait times
Solutions:
- Use SSDs for message storage
- Optimize fsync settings (consider trade-offs)
- Use lazy queues for non-critical workloads
- Consider using streaming queues for high-throughput scenarios
# RabbitMQ configuration for I/O-bound workloads
# In rabbitmq.conf:
# Reduce fsync frequency (at the cost of potential message loss on crash)
queue_index_embed_msgs_below = 10240
queue_index_sync_interval = 10000
# For low-latency but high-throughput workloads
disk_free_limit.relative = 1.5
CPU Limitations
Symptoms:
- High CPU usage across all cores
- Throughput scales linearly with CPU cores up to a point
Solutions:
- Add more CPU cores
- Scale horizontally (add more RabbitMQ nodes)
- Optimize message routing (fewer bindings and exchanges)
- Use simpler exchange types where possible
Memory Pressure
Symptoms:
- Flow control activated
- High memory usage
- Declining performance over time
Solutions:
- Increase memory limits
- Ensure consumers keep up with producers
- Set appropriate TTL for messages
- Use lazy queues for large backlogs
# Memory optimization in rabbitmq.conf
vm_memory_high_watermark.relative = 0.6
vm_memory_high_watermark_paging_ratio = 0.8
Best Practices for Reliable Benchmarks
- Isolate your environment: Run benchmarks in an environment similar to production
- Warm up the system: Let RabbitMQ stabilize before measuring
- Run long enough: Short tests can be misleading; aim for minutes, not seconds
- Test one variable at a time: Change only one parameter between benchmark runs
- Monitor all metrics: Look beyond throughput—check CPU, memory, disk, and network
- Repeat tests: Run each test multiple times to ensure consistency
- Test failure scenarios: See how the system behaves during node failures
- Test with realistic data: Use message sizes and patterns similar to your actual workload
Practical Examples
High-Throughput Event Processing
For systems processing millions of events per hour:
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 20 \
--consumers 50 \
--queue events-queue \
--size 512 \
--flag persistent \
--auto-delete false \
--queue-args "x-queue-type=quorum,x-max-length-bytes=1073741824" \
--consumer-rate 0 \
--producer-rate 0 \
--time 600 \
--producer-random-start-delay 60 \
--qos 1000
Low-Latency Trading System
For systems where message delivery speed is critical:
java -jar rabbitmq-perf-test.jar --uri amqp://guest:guest@localhost \
--producers 5 \
--consumers 5 \
--queue trades-queue \
--size 256 \
--flag mandatory \
--flag immediate \
--auto-delete false \
--queue-args "x-queue-type=classic,x-max-priority=10" \
--consumer-rate 0 \
--producer-rate 0 \
--time 300 \
--confirm 1 \
--confirm-timeout 10 \
--qos 1
Summary
Effective RabbitMQ benchmarking is essential for building reliable, high-performance messaging systems. By measuring key metrics like throughput, latency, and resource utilization, you can identify bottlenecks and optimize your setup for specific workloads.
Remember these key points:
- Use appropriate tools like PerfTest for consistent results
- Test various scenarios relevant to your use case
- Monitor all system resources during benchmarks
- Make incremental changes and retest
- Apply findings to optimize your RabbitMQ configuration
Benchmarking is not a one-time activity but should be part of your continuous improvement process, especially as your messaging needs evolve.
Additional Resources
To continue learning about RabbitMQ benchmarking:
- RabbitMQ PerfTest GitHub Repository
- RabbitMQ Performance Documentation
- PerfTest's Metrics Documentation
Exercises
- Run a basic benchmark with different queue types (classic, quorum, and stream) and compare their performance characteristics.
- Benchmark how message size affects throughput by testing with 100B, 1KB, 10KB, and 100KB messages.
- Compare the performance impact of different acknowledgment strategies (auto-ack vs. manual ack with varying batch sizes).
- Create a benchmark that simulates your expected production load and identify potential bottlenecks.
- Build a Grafana dashboard to visualize your RabbitMQ benchmark results using the Prometheus metrics endpoint.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)