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
| Setting | Purpose |
|---|---|
max_route_in_flight | Maximum concurrent checkouts for one route key. |
max_route_waiters | Maximum queued waiters for one route key. |
max_checkout_waiters | Global checkout waiter cap. |
pool_max_size | Maximum number of backend connections in one pool, also bounded by max_backends. |
pool_min_idle | Minimum idle connections retained by the lifecycle reaper. |
pool_idle_timeout_ms | Maximum idle age before an idle backend becomes eligible for eviction. |
pool_max_lifetime_ms | Maximum backend age before an idle backend becomes eligible for eviction. |
checkout_timeout_ms | Maximum backend checkout wait. |
query_timeout_ms | Maximum time for an assigned query cycle. |
idle_client_timeout_ms | Maximum idle client lifetime. |
idle_transaction_timeout_ms | Maximum idle time while pinned in a transaction. |
max_client_buffer_bytes | Client-side buffer cap. |
max_backend_buffer_bytes | Backend response buffer cap. |
overload_error_code | SQLSTATE 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_totalpg_kinetic_route_checkout_wait_mspg_kinetic_route_in_flightpg_kinetic_route_waitingpg_kinetic_timeout_totalpg_kinetic_buffer_limit_totalpg_kinetic_pool_connections{state="active"}andpg_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.