CMD Guide
HomeSystem DesignAPI Gateway

Scalability

Scalability for an API gateway is not the same problem as scaling a generic stateless service. Every request in the system passes through the gateway tier, so three things are unique to it: the gateway's own node count directly multiplies backend connection load, its rate-limiting state either lives per-node or has to be kept in sync across nodes, and its capacity math has to account for headroom that never touches live traffic (spares held back for rolling deploys). Getting these gateway-specific mechanics wrong is a common source of outages that look like backend problems but are actually caused by how the gateway tier scaled.

Horizontal vs. vertical scaling of the gateway tier

Horizontal scaling (scaling out) adds more gateway nodes behind the load balancer. This is the default for gateways because they are usually stateless with respect to application data — any node can handle any request — so adding nodes linearly increases request throughput without a single point of failure. Vertical scaling (scaling up) gives each gateway node more CPU/memory, which helps with per-request costs (TLS termination, request transformation, header parsing) but hits a hardware ceiling and still leaves a single node as a failure domain. In practice, gateway fleets scale horizontally as the primary lever and vertically only to raise the per-node capacity number that horizontal scaling then multiplies.

Statelessness is what makes horizontal scaling possible

A gateway can only run as N interchangeable nodes behind a load balancer if no request depends on which node handled the previous one. That means keeping the node itself stateless and pushing anything request-spanning out to a shared store: rate-limit counters, session/auth tokens, and cached responses all go to something like Redis, so any instance can serve any request. Connection pools to backends are the one piece of state that necessarily lives per node. When state is externalized this way, adding a node is free — the LB just starts routing to it — and losing a node loses no data.

Gateway-specific scaling mechanics

Worked example: sizing the gateway fleet

Suppose the gateway must sustain a steady peak of 60,000 requests/sec, and load testing shows one gateway node sustainably handles 3,000 requests/sec before p99 latency degrades.

QuantityValue
Steady peak traffic60,000 requests/sec
Sustainable throughput per gateway node3,000 requests/sec
Nodes needed to cover steady peak (60,000 ÷ 3,000)20 nodes
Spares reserved for rolling deploys (never removed from rotation as a block)+2 nodes
Total fleet size provisioned22 nodes

Which number the rest of this page uses, and why: 22 is what you provision and pay for. 20 is what is actually carrying live traffic at steady peak — the 2 spares exist purely so a rolling deploy can pull one batch of nodes out of rotation without ever dropping below 20 serving nodes; in normal operation they sit idle or mid-rollout, not serving production traffic. Every load-driven calculation below — backend connection counts, concurrency estimates — is therefore computed against the 20 serving nodes, not the 22 provisioned nodes. The one place the 22-node total matters is the brief window mid-rollout when both the outgoing and incoming batches are live at once; that ceiling is called out explicitly where it applies, rather than mixed silently into the steady-state numbers.

Load balancer routing to N stateless gateway nodes that share a Redis state store and each fan out pooled connections to 10 backend services, giving 20 serving nodes times 10 services times 30 connections equals 6,000 backend connections at steady peak
Load balancer routing to N stateless gateway nodes that share a Redis state store and each fan out pooled connections to 10 backend services, giving 20 serving nodes times 10 services times 30 connections equals 6,000 backend connections at steady peak

Backend connection fan-out

Because pools are per-node, steady-peak backend connections are driven by the 20 serving nodes, not the 22 provisioned: 20 serving nodes × 10 backend services × 30 pooled connections per service = 6,000 backend connections at steady peak.

Estimating in-flight concurrency with Little's Law

Little's Law states L = λ × W, where λ is the arrival rate and W is the mean (average) sojourn time a request spends in the system. Applied with the true average backend latency, it gives the actual expected number of concurrent in-flight requests.

A common shortcut is to plug in the p99 latency instead, because it is the number already on the latency dashboard: 60,000 requests/sec × 40 ms p99 backend latency = 2,400 estimated concurrent in-flight requests. This is not a literal Little's Law result — the law's W term is an average, not a percentile, and p99 latency is always greater than or equal to mean latency, so substituting it produces a deliberately conservative, inflated concurrency estimate rather than the true average. That conservatism is a defensible capacity-planning heuristic for sizing worker pools or connection limits with safety margin, but it should be labeled as an approximation, not presented as the formula's exact output. For contrast, if the mean backend latency is 12 ms, the literal Little's Law figure is 60,000 × 0.012 = 720 concurrent — about a third of the p99-based estimate. Pick the number that matches your intent and name it correctly: "720, the average concurrency by Little's Law" versus "2,400, a p99-based conservative sizing estimate."

Pitfalls

Selection and trade-offs

Takeaways


Sources: Little, J. D. C. (1961), "A Proof for the Queuing Formula: L = λW," Operations Research 9(3), for Little's Law and the mean-sojourn-time requirement on W; standard distributed-systems capacity-planning practice (per-node connection pooling, local-vs-shared rate-limit state, stateless-service scaling) as in the Google SRE Book and Designing Data-Intensive Applications (Kleppmann). Re-authored/Deepened for this guide.

🤖 Don't fully get this? Learn it with Claude

Stuck on Scalability? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Scalability** (System Design) and want to truly understand it. Explain Scalability from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Scalability** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Scalability** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Scalability** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes