Back Pressure
Back pressure is when a downstream component signals upstream to slow down because it can't keep up. Without it, a slow consumer causes unbounded queue growth, OOM crashes, and cascading failures. With it, the system degrades gracefully under load.
How it works
Imagine a water pipe. If the faucet (producer) pours faster than the drain (consumer) can drain, water backs up. In plumbing, this is back pressure. In software, it's the same: if a producer sends faster than a consumer can process, work piles up somewhere.
Without back pressure, that 'somewhere' is an unbounded queue or an ever-growing connection pool. Eventually, memory runs out and the system crashes. With back pressure, the consumer tells the producer 'slow down' — and the producer does.
Back pressure mechanisms:
- Bounded queues: queue has a max size. When full, the producer blocks (synchronous) or gets rejected (async).
- Reactive streams: the consumer pulls from the producer (pull-based) rather than the producer pushing. The consumer only requests what it can handle.
- HTTP 429 Too Many Requests: the server tells the client 'slow down'. The client must respect the
Retry-Afterheader. - TCP flow control: the OS handles this at the network layer — the receiver advertises a window size, and the sender doesn't exceed it.
- Message broker prefetch limits: the consumer only receives N messages at a time (e.g., Kafka
max.poll.records, RabbitMQprefetch_count).
When a queue is full, you have two choices: block the producer (synchronous back pressure) or reject the request (fail fast). Failing fast is usually better — a 429 error tells the client 'try again later', and the system stays responsive. Blocking causes threads to pile up and cascading failures.
Your API has an unbounded in-memory queue for processing requests. Under heavy load, what happens?
Pick one answer.
A consumer can process 100 messages per second. The producer sends 200 per second. Which back pressure mechanism prevents the queue from growing unbounded?
Pick one answer.
Engineering mental model
Mental model. Think of Back Pressure as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Back Pressure mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing Back Pressure, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
// Pseudocode
request = receive()
result = back_pressure(request)
return result
// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: Back Pressure
Change the variables below and predict what breaks first in Back Pressure. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on Back Pressure, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using Back Pressure. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using Back Pressure?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses Back Pressure, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose Back Pressure, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
For Back Pressure, treat the system as a control loop: observe load and failure, choose a bounded response, and measure whether the response stabilizes the system instead of simply moving the bottleneck somewhere else.
Numerical sanity check
When estimating capacity, distinguish average from peak. If average traffic is 4,000 RPS and the observed peak-to-average factor is 3×, design the first pass around roughly 12,000 RPS, then leave headroom for failure and growth.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
What is the earliest signal that Back Pressure is becoming the bottleneck: latency, saturation, errors, queue depth, or something else? Why?
Pick one answer.
What you gain, what you pay
- +Prevents OOM crashes under load — queues stay bounded.
- +Graceful degradation — system slows down instead of crashing.
- +Protects downstream services from being overwhelmed.
- +Natural rate limiting — the consumer's speed sets the system's speed.
- −Can cause rejected requests (429) — users see errors under load.
- −Adds latency — when the queue is near-full, requests wait longer.
- −Requires client cooperation — clients must respect 429 and Retry-After.
- −Hard to tune — queue size that's too small causes false rejections; too large causes latency.
How this breaks in production
- Unbounded queue — OOM crash under load.
- Queue too large — high latency before back pressure kicks in.
- Client ignores 429 — keeps hammering, causing the queue to stay full.
- Head-of-line blocking — one slow request blocks the whole queue.
Don't fall into these traps
- •Using unbounded queues — always set a max size.
- •Blocking instead of rejecting — blocking causes thread exhaustion and cascading failures.
- •Not propagating back pressure — if service A applies back pressure to service B, B must propagate it to its callers.
Real systems using this
How real systems implement this
- Reactive Streams (RxJava, Project Reactor) — Pull-based back pressure: the consumer requests N items, the producer sends only N. The consumer controls the flow.
- Kafka consumer — prefetch limit (max.poll.records) bounds how many messages the consumer receives at once. If processing is slow, the consumer doesn't poll for more.
Practice saying it out loud
- Q1What is back pressure? Why is it important?
- Q2How do you handle a producer that's faster than the consumer?
- Q3What happens if you use an unbounded queue under load?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Rate Limiting