The message arrives from product with an exclamation point: the new feature launches in three weeks, marketing is behind it, and checkout-service should expect 3x traffic. Can infrastructure handle it?

Everyone looks at checkout-service. Its autoscaling is tested, its error budget is healthy, its dashboard is a wall of green. “We’re good,” someone says.

You are probably not good. And the reason has nothing to do with checkout-service.

The bottleneck is never the headline service

The service in the launch announcement is the service that got attention: load-tested, autoscaled, dashboarded, right-sized. Attention is exactly why it will survive. Capacity incidents come from the places attention never reached, and those places sit downstream, in the dependency chain the headline service drags behind it.

The repeat offenders are boringly consistent:

  • Database connection pools. The app tier autoscales from 10 instances to 30; each instance opens its pool; the database’s max connections was set in 2024 and does not autoscale with the group. The math crosses somewhere around 2x, and everything upstream of the database experiences it as mysterious latency.
  • Shared caches. The Redis cluster that checkout shares with three other services has memory and connection ceilings that were fine at 1x. At 3x, evictions spike and every co-tenant service degrades at once, which looks like four incidents instead of one.
  • NAT gateways and egress paths. Every additional instance pushes more traffic through the same network chokepoints. Throughput caps and port exhaustion arrive precisely when everything else is scaling correctly.
  • Third-party rate limits. The payment processor, the tax API, the email provider: their limits are in a contract, not in your console, and they do not know about your launch.
  • Account-level quotas. Instance count limits, API request rates, IP address pools. Invisible until the autoscaler asks for capacity and the cloud says no.

Notice the pattern: autoscaling does not remove the problem; it relocates it. Scaling the app tier multiplies the pressure on everything behind the app tier. The service survives, and its dependencies inherit the spike.

Capacity planning is a graph traversal with arithmetic

The correct method is almost embarrassingly mechanical. Start at the service receiving the traffic. Walk every hop downstream: services, databases, caches, queues, gateways, third-party APIs, including hops that pass through other services. At each component, attach its actual configured limit, not the folklore version. Multiply the projected load through each hop. The components whose limits are crossed first, and at what multiplier, are your answer: “orders-db saturates at 2.1x, the NAT gateway at 2.6x, everything else clears 3x.”

Two hard parts hide in that paragraph. The first is that the dependency map has to be true, and in most organizations the true map lives in fragments across Terraform, consoles, and the memory of whoever built each piece. The second is that “actual configured limit” requires checking live configuration, not design docs.

Both hard parts are context problems, which is why we lean on the Cloud Intelligence Graph™ for this. Oscar already maintains the dependency structure and can read the live limits, so “product expects 3x traffic to checkout-service, what breaks first?” becomes a traversal it runs in minutes: the ordered bottleneck list, with the configured limit and the crossing point for each, before anyone spends a day wiring up a load test.

Load tests validate the map. They do not replace it.

None of this argues against load testing; it argues about sequence. A load test is expensive to build and answers the question for one traffic shape on one day. Run it after you know where the cliffs are, to confirm the two or three crossing points you predicted, rather than as a fishing expedition for cliffs you have not mapped.

Three weeks is plenty, if you spend the first day on the graph instead of the last night on the incident. Ask the question early: what actually breaks at 3x? If nobody can answer with a component name and a multiplier, that is the first thing to fix, and it takes about thirty minutes to start.

Key Takeaways

Key points

  • Capacity planning fails when it scopes to the service receiving the traffic instead of the dependency chain behind it.
  • The classic first casualties: database connection pools, shared caches, NAT gateways, third-party rate limits, and account-level quotas.
  • Autoscaling amplifies downstream pressure: more app instances means more connections, more egress, and more API calls hitting fixed limits.
  • The right method is mechanical: walk every hop downstream, attach each component's actual configured limit, and multiply.
  • Load tests validate the map; they do not replace it. Test after you know where the cliffs are, not to discover them.

Frequently Asked Questions

How do I figure out what will break when traffic increases?
Trace the full dependency chain of the service receiving the traffic: every database, cache, queue, gateway, and third-party API it touches, directly or through other services. For each component, find its actual configured limit (connection pools, throughput caps, rate limits, account quotas), then model the multiplied load at each hop. The components whose limits are crossed earliest are your launch-day bottlenecks, and they are usually two or more hops from the headline service.
Why do autoscaled services still fail under load?
Autoscaling multiplies the pressure a service puts on everything behind it. Doubling app instances doubles database connections, cache traffic, NAT egress, and outbound API calls, and those downstream components often have fixed limits that do not scale with the group. The app tier survives; its dependencies inherit the spike.
Can Oscar help with capacity planning?
Yes. Ask Oscar what breaks if traffic to a service triples and it walks the dependency graph it has built of your environment, checks configured limits on each downstream component, and returns the ordered list of bottlenecks with the evidence, before you spend a day building a load test.
Brian Kathman is the CEO and co-founder of OpsCanvas. Every capacity story he has lived follows the pattern in this post: the headline service holds, and something unglamorous two or three hops away folds first. Walking the dependency graph with real limits attached is the whole discipline. The teams that do it before launch call it planning; the teams that do it after call it a post-mortem.