Free — no signup required

Backpressure: Don't Let the Sink Overflow

3 min read

The Plumbing Analogy

Imagine a kitchen sink. The faucet pours water in (incoming requests), and the drain lets water out (processed requests).

If you pour water faster than the drain can handle, the water level rises (the queue fills up). Eventually, the sink overflows onto the floor — in software terms, the service crashes with an Out of Memory (OOM) error, or requests time out after waiting in a queue for minutes.

The naive solution is to make the sink bigger (add more memory, grow the queue). But this just delays the crash and makes it worse when it comes — now you have millions of requests queued up, all of which will time out at once.

Pushing Back

Backpressure is the mechanism that stops this from happening. It is the ability of a consumer to signal to a producer that it is overwhelmed and needs the producer to slow down or stop sending work.

Instead of accepting requests into an infinitely growing queue until it crashes, a service under stress should actively reject new work early, while it still has capacity to send a clean error response.

How to Implement Backpressure

Bounded Queues with Fast Rejection:
Set a hard limit on your request queue size. If the queue is full, immediately reject new requests with an HTTP 503 Service Unavailable response instead of letting them wait. This is far better than letting requests queue up for minutes and then timing out — a fast 503 lets the caller decide what to do (retry later, show a user-facing message, route to a fallback). In practice this is a fixed-capacity queue with a non-blocking insert: if the insert fails because the queue is full, the handler immediately returns 503 instead of waiting.

TCP Flow Control (Built-in Backpressure):
At the network level, TCP automatically applies backpressure through its receive window mechanism. If the receiving application is slow to read data, the TCP stack shrinks the advertised window size, telling the sender to slow down. This is why a slow consumer in a TCP stream doesn't cause the sender to crash — TCP throttles it automatically.

Message Queue Prefetch (Consumer-Side Control):
In systems like RabbitMQ or Kafka, consumers can control how much work they accept at once. A RabbitMQ consumer can set prefetch_count=1, meaning the broker will not send the next message until the consumer acknowledges the current one. This prevents the consumer from being flooded.

Why Backpressure Matters Architecturally

By applying backpressure, you shift the problem upstream to the caller, who is better equipped to handle it. The caller can retry later, queue the work on its own side, or degrade gracefully. Without backpressure, a slow downstream service silently absorbs more and more work until it collapses — taking the entire call chain down with it.

Interview Tip

A common SRE interview question is: "A downstream service is slow. Your service keeps accepting requests and queuing them. Eventually your service OOMs and crashes. How do you fix this?" The answer has two parts: (1) Bounded queues to stop accepting work when full, and (2) Circuit breakers to stop calling the downstream service when it is known to be unhealthy. Backpressure and circuit breaking are complementary — backpressure protects you from being overwhelmed by callers above you; circuit breakers protect you from being dragged down by failures below you.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free