Introduction
RabbitMQ is fast, but performance can go down if it is not configured well.
Two key metrics are:
- Throughput: how many messages per second RabbitMQ can handle.
- Latency: how long it takes for a message to move from producer to consumer.
This article explains simple ways to tune RabbitMQ for better throughput and lower latency. This article is a continuation of my earlier posts on High Availability in RabbitMQ: Clustering and Mirrored Queues Explained and Scaling Microservices with RabbitMQ: Patterns and Best Practices. Together, they give a broader view of RabbitMQ performance, reliability, and scaling patterns.
Hardware and System Settings
- Use SSD storage
- Faster disk = faster persistence for durable queues.
- Increase memory
- RabbitMQ keeps messages in RAM as much as possible. More RAM = faster.
- Tune file descriptors
- RabbitMQ needs many open file handles for connections.
- Increase
ulimit -n
to something like65535
.
- Use multiple cores
- RabbitMQ is multi-threaded. More CPU cores = more parallel handling.
RabbitMQ Configuration
a. Prefetch Count (QoS)
- Controls how many messages a consumer can receive before ack.
- Low value = fairness but slower.
- Higher value = more throughput, but risk of overload.
Example in Go:
ch.Qos(50, 0, false) // allow 50 unacked messages per consumer
Publisher Confirms vs Transactions
RabbitMQ supports two ways to make sure published messages are safely stored:
- Transactions
- Similar to database transactions.
- Producer starts a transaction, publishes messages, and commits.
- If commit fails, messages are rolled back.
- Very reliable but slow, because it blocks.
ch.Tx() // start transaction err = ch.Publish("", "task_queue", false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte("Hello Transaction!"), }) if err != nil { ch.TxRollback() log.Println("Transaction rolled back") } else { ch.TxCommit() log.Println("Transaction committed") }
- Publisher Confirms
- More modern and faster.
- Enable confirms with
ch.Confirm(false)
. - Broker sends ACK/NACK after message is stored.
- Works asynchronously, much lighter than transactions.
ch.Confirm(false) // enable confirms ackChan := ch.NotifyPublish(make(chan amqp.Confirmation, 1)) err = ch.Publish("", "task_queue", false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte("Hello Confirm!"), }) if err != nil { log.Fatal("Publish failed:", err) } confirm := <-ackChan if confirm.Ack { log.Println("Message confirmed by broker") } else { log.Println("Message not confirmed (NACK)") }
Comparison
Feature | Transactions (Tx) | Publisher Confirms |
---|---|---|
Reliability | Strong | Strong |
Speed | Slow | Fast |
Behavior | Blocking | Async |
Best Use Case | Rare | Recommended |
Connection Management
- Reuse channels instead of creating too many.
- Avoid opening thousands of short-lived connections.
- Use a connection pool for efficiency.
Category: RabbitMQ