Envoy circuit breaker: intermittent upstream connection pool exhaustion under aggregate limits
0 reputation · 20 Oct 2023, 03:49 UTC
0 reputation · 20 Oct 2023, 03:49 UTC
Envoy bounds upstream connection pressure through per-cluster, per-priority circuit-breaker limits such as max_connections, max_pending_requests, max_requests, and max_retries. When a limit is reached, Envoy rejects or queues work instead of opening more connections. Intermittent exhaustion appears in cluster-level counters: upstream_cx_overflow (connection limit hit), upstream_rq_pending_overflow (pending-request limit hit), and upstream_rq_retry_overflow, alongside gauges like upstream_cx_active and upstream_rq_pending_active.
max_requests_per_connection and the HTTP/2 max_concurrent_streams setting, forcing connection churn that may masquerade as a connection-count problem.Which binding constraint—connection count (max_connections) or concurrent stream/request capacity (max_pending_requests, max_requests_per_connection, HTTP/2 max concurrent streams)—is the primary driver of the observed overflow pattern? Does the per-priority exhaustion behavior warrant explicit per-priority circuit-breaker overrides, or should the aggregate limits be restructured? What controlled load-test methodology best isolates aggregate-limit exhaustion from per-host or upstream-imposed limits?
31275 reputation · 20 Oct 2023, 04:40 UTC
The primary driver of overflow is identified by which specific Envoy counter is incrementing during the exhaustion event. Because Envoy applies limits at the cluster level rather than the endpoint level, the pattern of overflow reveals the bottleneck:
upstream_cx_overflow: The max_connections limit is the driver. This occurs when the total number of active TCP connections across all hosts in the cluster exceeds the threshold.upstream_rq_pending_overflow: The max_pending_requests limit is the driver. This typically indicates that connections are being established, but the upstream is too slow to accept them, filling the queue.upstream_cx_active remains low but you see request-level failures, the bottleneck is likely the HTTP/2 max_concurrent_streams setting or max_requests_per_connection. The latter forces connection churn, which can cause intermittent spikes in upstream_cx_overflow as Envoy rapidly opens and closes connections.Whether to use per-priority overrides depends on your traffic criticality. Aggregate limits are shared; if low-priority background traffic spikes, it can starve high-priority user requests.
Use per-priority overrides if: You have a clear distinction between traffic classes (e.g., high for user-facing API calls, low for asynchronous telemetry) and need to guarantee headroom for the former regardless of the latter's volume.
Restructure aggregate limits if: The exhaustion is caused by a general mismatch between Envoy's capacity and the upstream's ability to handle concurrent load. Simply increasing limits without scaling the backend may shift the failure from Envoy to the upstream TCP backlog.
To isolate aggregate-limit exhaustion from per-host or upstream-imposed limits, use a controlled reduction of the host pool:
upstream_cx_active to max_connections.max_requests_per_connection to a very low value to simulate high connection turnover and verify if this triggers upstream_cx_overflow despite low concurrent request volume.To refine this recommendation, please provide the current value of max_requests_per_connection and whether you are using HTTP/1.1 or HTTP/2 for upstream communication.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.