
Published on 11 min read

Photo by Taylor Vick on Unsplash
An API gateway looks like a thin proxy until the night it becomes the outage. Centralization is the point: one place for TLS, auth, rate limits, routing, and policy. Centralization is also the risk: every request shares the same finite event-loop budget, connection pools, and blast radius.
Microsoft’s Gateway Offloading guidance says it plainly: keep the gateway highly available, size it so it is not a bottleneck, and never push business logic into it. Canva’s public incident report for 12 November 2024 shows what happens when that shared front door saturates — roughly 1.5 million requests per second, about 3× typical peak, combined with a telemetry lock that starved the Netty event loop until Linux OOM-killed the fleet.
This article is a diagnostic checklist of six problems gateways already suffer from in production — and how to fix them before the next thundering herd.
An API gateway is the edge facade in front of one or more backends. Typical duties: terminate TLS, authenticate callers, enforce quotas, route by path or header, emit metrics and traces, optionally transform headers or paths.
It is not a substitute for:
If you treat it as a passive pipe, you will miss its failure modes. If you treat it as an application server, you will invent new ones.
Symptom: The site is “down” even though most backends are healthy. Autoscaling adds capacity that dies as soon as it becomes healthy.
Why it happens: One gateway cluster fronts everything. A spike, a blocking call on the event loop, or memory pressure takes the whole public API with it. Microsoft warns explicitly to avoid single points of failure and to keep the gateway from becoming the bottleneck.
Canva’s outage is the reference case. A CDN path delay queued 270,000+ clients on one asset. When the asset finally arrived, clients resumed and hit the API Gateway with a synchronized herd. Load balancers opened more connections into already overloaded tasks. Off-heap memory grew; the OOM killer cleared containers faster than autoscaling could refill them. Mitigation only worked after traffic was blocked at the CDN so new tasks could start cold.
What to do:
503) before queues eat the fleetSaturation is not “the gateway is slow.” It is “the gateway is the choke point for the product.”
Symptom: Clients see 504 / abandoned requests while the gateway still holds upstream work. Connection pools fill. Latency climbs, then everything fails together.
Why it happens: Timeouts are set once and forgotten. If the gateway waits as long as (or longer than) the client, you keep spending gateway concurrency on requests the user already abandoned. Slow upstreams then fill pools; pending queues grow; new work is rejected while backends stay overloaded — a self-reinforcing loop.
AWS documents the hard edge of this class of failure for Amazon API Gateway: when an integration exceeds the configured maximum wait, callers get HTTP 504 (“Endpoint request timed out”). The default integration timeout has long been 29 seconds for many REST setups; as of June 2024 AWS allows raising it for Regional and private REST APIs (often with throttle-quota trade-offs). Raising the ceiling without fixing the hierarchy only keeps zombies alive longer.
What to do:
client timeout > gateway→upstream timeout > per-try timeout503 over a 30-second wait that fails anyway (Envoy tracks max_pending_requests for this reason)See also our reference on timeouts, retries, jitter, and backoff.
Symptom: Upstream error rates are elevated, then suddenly multiplied. Gateway CPU and upstream QPS spike together. Recovery takes longer than the original fault.
Why it happens: Retries are selfish: they spend more of the server’s time to improve your success rate. AWS Well-Architected REL05-BP03 calls out retries without backoff, jitter, and caps — and especially retries at multiple layers that compound into a storm. Envoy’s docs say the same in gateway terms: limit outstanding retries so sporadic failures can still be retried, but volume cannot explode into cascading failure. Prefer a retry budget (default guidance often centers on roughly 20% of active + pending traffic as concurrent retries) over a static max_retries alone.
What to do:
connect errors, timeouts, selected 5xx / 429) — not validation or auth 4xxretry_budget overrides static retry circuit breakers when set)max_ejection_percent so a correlated bad deploy cannot eject the entire cluster (Envoy defaults this ceiling to 10%)Symptom: Every product change needs a gateway deploy. Plugins parse JSON bodies, reshape fields, and encode domain rules. Latency and cognitive load climb together.
Why it happens: Offloading cross-cutting concerns is correct. Offloading business logic is not. Microsoft’s Gateway Offloading pattern states it without hedging: “Business logic should never be offloaded to the gateway.” Header injection, path rewrites for migrations, and correlation IDs belong at the edge. Filtering response fields by product semantics, aggregating five services into one “screen DTO,” or encoding entitlement rules in Lua/JS plugins duplicate the domain in the worst place: the shared hot path.
What to do:
| Belongs in the gateway | Belongs in services / BFF |
|---|---|
| TLS, authn (identity), coarse rate limits | Fine-grained authz with resource context |
| Routing, API versioning paths | Domain validation and workflows |
| Correlation IDs, strip internal headers | Response shaping for a specific UI |
| Protocol translation (e.g. REST↔gRPC at the edge) | Multi-service aggregation for a product screen |
Keep the gateway structurally aware and semantically blind. If a change needs a product owner’s approval more than an SRE’s, it probably should not live in gateway config.
Symptom: Dashboards show “API red” with no split between edge overhead and upstream time. Or the gateway looks fine until load rises — then a “harmless” metric library locks threads and throughput collapses.
Why it happens: Gateways often emit one success/error rate and stop. You cannot tell whether clients wait on TLS, plugins, auth round-trips, or the backend. Worse: synchronous logging, token introspection on every request, or contended locks inside telemetry run on the event loop. Canva’s postmortem is explicit: Netty event-loop threads must not block; a telemetry re-registration under a lock reduced per-task throughput right when the herd arrived.
What to do:
upstream_rq_retry_overflow and pending overflows)If you cannot answer “is the edge sick or is payments sick?” in under a minute, this problem is already yours.
Symptom: Rate limits that look correct on paper are trivially bypassed. Backends are reachable without the gateway. The Admin / control API is exposed wider than anyone intended.
Why it happens: Three classic gaps:
N replicas behave like N independent limits. Shared stores (for example Redis) fix global caps but add latency and a new dependency; choose the algorithm deliberately (token bucket is usually what public APIs want). Always return 429 with Retry-After (or equivalent) so clients do not retry immediately and amplify load.0.0.0.0:8001 can “seriously compromise the security of your whole Kong cluster.” Trend Micro’s case study on Kong misconfigurations makes the same point: Admin API and datastore access must stay tightly scoped.What to do:
The data plane is only as trustworthy as the control plane that configures it.
spike / deploy / CDN blip
│
▼
saturation (1) ←── blocking telemetry / plugins (5)
│
├── broken timeouts (2) → pool exhaustion
├── unbounded retries (3) → load ×N
└── god-gateway work (4) → less headroom
│
▼
control gaps (6) → bypass or unsheddable trafficFixing only retries while the event loop blocks — or only HA while timeouts are inverted — leaves the amplifier intact.
It is a shared failure domain unless you invest in redundancy, isolation, and shedding. Multiple instances behind a load balancer remove a single process as SPOF, but one shared config, one telemetry bug, or one global herd can still take the product offline — as Canva showed. Treat availability of the gateway as a product requirement, not a checkbox.
Sometimes, for idempotent GETs and safe transient errors — with budgets. Prefer one retry layer. Gateway retries that stack on client retries and mesh retries are a common path to storms (AWS REL05-BP03).
Overlap is fine; duplicate retry + authz logic in all three is not.
If you see upstream work completing after the client has disconnected, growing pending queues under slow backends, or frequent 504 while integrations still run past the client’s patience, the budget is inverted or missing. Measure client timeout, gateway timeout, and upstream duration on the same trace.
Your API gateway is already under pressure from six directions: shared saturation, inverted timeouts, unbudgeted retries, domain logic at the edge, opaque or blocking observability, and soft hardening of data and control planes. None of these are theoretical — they show up in vendor docs, architecture patterns, and public postmortems.
Pick one production route this week. Verify the timeout hierarchy, confirm retries are budgeted in a single layer, measure gateway overhead separately from upstream time, and confirm Admin and backend networks cannot bypass policy. The goal is not a smarter god-proxy. It is a boring, shedding, observable edge that fails in small pieces instead of taking the product with it.