# TCP Congestion Control

TCP's mechanism for preventing network collapse by throttling how fast a sender pushes data. Without it, packet loss causes retransmissions that cause more packet loss — a feedback loop that took down the early internet in 1986.

## How it works

The sender maintains a **congestion window** (cwnd): the number of unacknowledged packets allowed in flight. This indirectly caps throughput because it limits how much data can be sent per round trip.

**Slow start** governs new connections. The window starts at 10 packets (per [RFC 6928](https://datatracker.ietf.org/doc/html/rfc6928)) and doubles each RTT — each ACK grows the window by one, and a full window's worth of ACKs arrives each round trip. Ten packets at typical ~1368-byte payloads means roughly 13 kB in the first RTT. See [[13kb-tcp-slow-start]] for a worked example.

**Congestion avoidance** kicks in after the first sign of loss. The window grows linearly (+1 packet per RTT) instead of exponentially, probing for capacity without overshooting.

Slow start plus congestion avoidance is a feedback controller — measure the error signal (loss), adjust the actuator (window size), repeat, and hope the loop settles instead of oscillating. Janert's [[feedback-control-for-computer-systems]] is the book that names the parts and gives the stability conditions, which is the thing you want the moment you write your own loop for an autoscaler or rate limiter.

## Loss detection matters

How loss is detected changes the response:

- **Duplicate ACKs** — the receiver is still getting packets, just not the one it wanted. The window halves and congestion avoidance continues. This is "fast retransmit."
- **Timeout** — nothing came back. Maybe the network is still full of the sender's packets. The window resets to 1 and slow start runs again up to half the pre-loss window ("slow start threshold").

The distinction reflects uncertainty: duplicate ACKs mean data is flowing, timeout means it might not be.

## Why it matters for the web

Because slow start limits the first RTT to ~13 kB, website performance depends heavily on what fits in that initial burst. Critical CSS and JavaScript should be inlined or kept small enough to arrive in the first flight. The often-cited "14.2 kB budget" is approximate — actual sizes vary with MTU, VLANs, HTTP headers, TLS overhead, and compression.

## TCP timer internals

TCP relies on internal kernel timers for connection lifecycle management — not just congestion control but also TIME_WAIT expiration, retransmission timeouts, and keepalive probes. On macOS, these timers depend on a single `uint32_t` counter (`tcp_now`) that overflows after 49.7 days of uptime, freezing the TCP clock and breaking TIME_WAIT garbage collection. See [[macos-tcp-time-bomb]] for the full analysis.
