Skip to main content

Backpressure And Overload

For platform engineers sizing PostgreSQL capacity and deciding what clients see during overload.

pg-kinetic uses route-aware backpressure so one noisy path does not consume all backend capacity. Overload should fail predictably instead of letting clients wait forever.

Route Keys

A route key groups traffic by:

  • database
  • user
  • application name
  • client address
  • query class

This makes queueing more useful than a single global counter. A bulk worker can saturate its own route without starving unrelated interactive traffic.

Limits

SettingPurpose
max_route_in_flightMaximum concurrent checkouts for one route key.
max_route_waitersMaximum queued waiters for one route key.
max_checkout_waitersGlobal checkout waiter cap.
pool_max_sizeMaximum number of backend connections in one pool, also bounded by max_backends.
pool_min_idleMinimum idle connections retained by the lifecycle reaper.
pool_idle_timeout_msMaximum idle age before an idle backend becomes eligible for eviction.
pool_max_lifetime_msMaximum backend age before an idle backend becomes eligible for eviction.
checkout_timeout_msMaximum backend checkout wait.
query_timeout_msMaximum time for an assigned query cycle.
idle_client_timeout_msMaximum idle client lifetime.
idle_transaction_timeout_msMaximum idle time while pinned in a transaction.
max_client_buffer_bytesClient-side buffer cap.
max_backend_buffer_bytesBackend response buffer cap.
overload_error_codeSQLSTATE returned when overload is rejected.

The default overload SQLSTATE is 53300, PostgreSQL's too many connections class.

Worked Example

Assume an API route has:

[capacity]
max_route_in_flight = 8
max_route_waiters = 4
checkout_timeout_ms = 250
overload_error_code = "53300"

When twelve matching client requests arrive while all eight allowed backend checkouts are already in flight, pg-kinetic admits four waiters. A thirteenth matching request is rejected immediately with SQLSTATE 53300 because the route queue is full. The client receives a PostgreSQL error response followed by ReadyForQuery, so normal PostgreSQL drivers surface it as a query error rather than a broken socket.

If one of the eight in-flight requests finishes within checkout_timeout_ms, the oldest waiter gets the backend and proceeds. If no backend becomes available before the timeout, that waiter is failed with the configured overload behavior and the timed_out counter increases for the route.

The important tradeoff is explicit: increasing max_route_waiters absorbs bursts but adds tail latency; decreasing it fails faster and protects interactive traffic from standing behind known-slow work. Increasing max_route_in_flight can improve throughput only when PostgreSQL has remaining CPU, memory, lock, and I/O headroom.

Failure Behavior

When a route is saturated, pg-kinetic returns an overload error. When a timeout or buffer limit fires, the proxy recovers the backend if the state is safe. If recovery cannot prove the backend is reusable, the backend is discarded.

This behavior protects the pool from returning contaminated backend state to a different client.

Observability

Watch these signals together:

  • pg_kinetic_backpressure_events_total
  • pg_kinetic_route_checkout_wait_ms
  • pg_kinetic_route_in_flight
  • pg_kinetic_route_waiting
  • pg_kinetic_timeout_total
  • pg_kinetic_buffer_limit_total
  • pg_kinetic_pool_connections{state="active"} and pg_kinetic_pool_connections{state="idle"}
  • pg_kinetic_pool_evictions_total

Admin views:

SHOW BACKPRESSURE;
SHOW LIMITS;
SHOW PERFORMANCE;

Sustained route waiters usually means capacity, query latency, or traffic isolation needs attention. A short spike during deploy or failover can be normal if readiness and drain behavior recover quickly.