A platform running thousands of concurrent isolated sessions starts seeing intermittent connection failures to external sites. Ports are available and CPU is low. What is the likely cause?
Show the full answer Hide the answer
The mechanism
Outbound connections through a NAT gateway are translated to a source port on the gateway's address. Ports are a finite resource per destination address, and a workload that opens very large numbers of simultaneous outbound connections — thousands of browser sessions each loading dozens of external resources — exhausts them.
The symptom is characteristic and misleading: intermittent connection failures with no local resource pressure. CPU is fine, memory is fine, the application logs a connection timeout, and everything appears healthy.
It is made worse by connections in TIME_WAIT, which hold their port allocation for a period after closing, so
the effective limit is reached well below the theoretical one.
The remedies
- More NAT addresses, which multiplies the available port space directly. The simplest fix and often sufficient.
- Distribute egress across multiple gateways, per availability zone or per workload class, which also contains the failure.
- Direct connectivity to high-volume destinations — private endpoints, peering, or a gateway endpoint for object storage — removing that traffic from NAT entirely. Often the largest single reduction, because a small number of destinations usually dominate.
- Connection pooling and reuse in the application, since the underlying cause is frequently a client creating a new connection per request.
- Shorter
TIME_WAITand connection reuse settings, with care, since they trade a small correctness margin for capacity.
The architectural lesson
Egress is a shared, finite, invisible resource, and it is one of very few resources that fails without any local signal. It belongs in capacity planning alongside CPU and memory, and it should be monitored explicitly — port allocation and NAT error counts — because nothing else in the stack will report it.
The same class of invisible shared limit includes connection tracking table size, ephemeral port ranges on individual hosts, and per-account API quotas at cloud providers. All of them fail as intermittent, unexplained errors, which is why they must be instrumented rather than discovered.