Skip to content
Devgo

Backpressure

A signal from a slower consumer to a faster producer to slow down, preventing unbounded buffering and memory blowups. It propagates upstream so the system finds a sustainable rate. Without it, queues grow until OOM or latency explodes.

When to use
  • Streaming pipelines, event ingestion, any producer faster than consumer.
  • Anywhere unbounded queues would hide problems until OOM.
When not to
  • Best-effort telemetry where dropping is preferable to slowing the app.
  • Spiky traffic you'd rather shed than throttle.

Definition

When a consumer can't keep up, it tells producers to send less (or blocks them). Reactive streams, TCP windows, and bounded queues all backpressure. The opposite is lossy drop or unbounded buffering.

Why it exists

Producer/consumer rate mismatch is the norm. Backpressure makes the mismatch explicit and bounded instead of silently queuing until failure.

How it works

Bounded queue: producer blocks or gets a 'slow down' error when full. Reactive streams: a Subscriber requests N items, Publisher emits only that many. TCP: receive window shrinks. The key is a bounded buffer plus a flow-control channel.

Scaling limits

Backpressure that propagates many hops can cause head-of-line blocking across a pipeline. End-to-end flow control across heterogeneous hops is hard to tune.

Cost shape

Cheap in principle. The cost is reduced throughput when intentionally slowing producers, which is the point.

Alternatives

  • Load shedding — Drops excess instead of slowing; lower latency for kept requests, lost work.
  • Unbounded queue — Absorbs spikes but hides lag and risks OOM.

Failure modes

  • Blocking a producer thread that holds a lock, causing deadlock.
  • Backpressure not propagating past a buffering hop, so the queue still grows.

,