RabbitMQ Prefetch and QoS

Prefetch and QoS (Quality of Service) control how many messages RabbitMQ sends to a consumer before the consumer must acknowledge at least one. Without a prefetch limit, RabbitMQ sends all available messages to the first consumer that connects, overwhelming it while other consumers sit idle. Prefetch is essential for balanced, fair message distribution.

The Waiter and Kitchen Analogy

A kitchen (RabbitMQ) has 20 dishes ready. Without any limit, the kitchen hands all 20 dishes to one waiter at once. The waiter stumbles, drops some, and cannot serve any table properly. With a prefetch limit of 3, each waiter handles 3 dishes at a time. Four waiters work simultaneously and every table gets served efficiently.

The Problem Without Prefetch

Queue: [msg1][msg2][msg3]...[msg100]

Consumer A connects first:
  RabbitMQ sends ALL 100 messages to Consumer A immediately
  Consumer A is overwhelmed

Consumer B connects later:
  Nothing left in queue for Consumer B
  Consumer B sits idle

This wastes Consumer B completely and creates a bottleneck at Consumer A.

The Solution: basic.qos with prefetch_count

Setting prefetch_count=1 tells RabbitMQ: "Do not give me more than 1 unacknowledged message at a time." RabbitMQ holds back the next message until the consumer acknowledges the current one.

channel.basic_qos(prefetch_count=1)
Queue: [msg1][msg2][msg3][msg4]

Consumer A (prefetch=1): receives msg1, processes, acks, receives msg3, ...
Consumer B (prefetch=1): receives msg2, processes, acks, receives msg4, ...

Both consumers work simultaneously. Work is balanced.

Choosing the Right Prefetch Value

Prefetch of 1 is the safest and most fair setting. However, it also means the consumer must complete a full network round trip (process + ack + wait for next message) before getting the next task. This adds latency overhead.

Higher prefetch values allow consumers to work on a batch of messages simultaneously, improving throughput at the cost of less precise load balancing.

prefetch_count = 1
  Best fairness, lowest throughput (one round trip per message)
  Use when tasks vary greatly in duration

prefetch_count = 10
  Better throughput, consumer holds up to 10 messages at once
  Use when tasks are fast and fairly uniform in duration

prefetch_count = 0 (unlimited)
  RabbitMQ sends all available messages immediately
  Never use in production with multiple consumers

Channel-Level vs Consumer-Level Prefetch

The basic.qos call has a global flag:

  • global=False (default): The prefetch limit applies per consumer on the channel. If a channel has 3 consumers and prefetch=10, each consumer gets up to 10 unacked messages (30 total on the channel).
  • global=True: The prefetch limit applies across all consumers on the channel combined. If prefetch=10 and there are 3 consumers, they share a pool of 10 total unacked messages.
channel.basic_qos(prefetch_count=10, global_qos=False)  # per consumer (default)
channel.basic_qos(prefetch_count=10, global_qos=True)   # per channel total

Prefetch and Slow Consumers

Prefetch prevents a slow consumer from monopolising the queue. Consider a queue with 3 consumers and a prefetch of 5:

Consumer A (fast): processes 5 messages in 1 second → acks → gets 5 more
Consumer B (slow): processes 1 message in 5 seconds → holds 5 messages
Consumer C (fast): processes 5 messages in 1 second → acks → gets 5 more

Consumer B's 5 messages are tied up. But A and C keep working.
Without prefetch, B could have held all 1000 messages.

Prefetch in the Work Queue Pattern

The work queue pattern (Topic 17) specifically recommends prefetch_count=1 with manual acknowledgements. This combination ensures:

  • Each worker gets one task at a time
  • The next task goes to the worker that finishes first
  • No worker is overloaded
  • No task is lost if a worker crashes

Finding the Right Prefetch Value in Practice

Test your system with different prefetch values and measure throughput (messages processed per second) and latency (time from publish to consume). A common starting approach:

  1. Start with prefetch=1 and measure baseline throughput.
  2. Increase to prefetch=5, 10, 20 and re-measure.
  3. Choose the lowest value that achieves acceptable throughput.

For most task queues with mixed task durations, prefetch between 1 and 10 gives the best balance. For bulk data pipelines with uniform, fast tasks, prefetch of 50 to 500 may be appropriate.

Monitoring Prefetch Effects

In the Management UI, check the Channels tab. Each channel shows its prefetch count and the number of unacked messages it currently holds. A channel at its prefetch limit (Unacked = Prefetch Count) means the consumer is processing at full capacity. If Unacked is always at the limit, consider increasing prefetch or adding more consumers.

Summary

Prefetch (set via basic.qos) limits how many unacknowledged messages a consumer holds at once. Without it, RabbitMQ floods the first consumer and starves the rest. Prefetch of 1 gives maximum fairness. Higher values improve throughput but reduce fairness across consumers. Use the global flag to apply limits per consumer or per channel. Always combine prefetch with manual acknowledgements for reliable, balanced message processing.

Leave a Comment

Your email address will not be published. Required fields are marked *