Module 12 · Transport layer · Lesson 3 of 5
Congestion control
How millions of independent senders share the internet without collapsing it: the congestion window, slow start, additive increase and multiplicative decrease, CUBIC and BBR, bufferbloat.
Why it matters
In 1986 the early internet suffered congestion collapse: links stayed full, but almost all the traffic was retransmissions, and useful throughput fell a thousandfold. Congestion control was the fix, and it is still why the internet works. For engineers it explains everyday behaviour: why a new connection starts slowly, why a small response is dominated by round trips and a large one by bandwidth, why throughput halves after a loss, and why latency spikes when a link is busy.
The idea
The network gives senders no explicit signal of how much capacity is free. So each TCP sender keeps a congestion window (cwnd), its own estimate of how many bytes it can safely have in flight, probes for more capacity by growing it, and backs off sharply when it sees signs of congestion, classically packet loss. Each sender acts alone, yet together they converge on sharing the bottleneck roughly fairly. The effective window is the smaller of the congestion window and the receiver's advertised window.
The classic phases
- 1
Slow start
A new connection starts with a small window, typically 10 segments (about 14 KB), and doubles it every round trip while ACKs arrive: exponential growth to find capacity quickly. - 2
Congestion avoidance
Past a threshold, growth becomes additive: about one segment per round trip, gently probing for more. - 3
Multiplicative decrease on loss
On loss detected by duplicate ACKs, the window is cut (halved in classic Reno, by 30 percent in CUBIC) and growth resumes. On a retransmission timeout, the window collapses to one segment and slow start begins again.
What this means in practice
A fresh connection with a 10-segment initial window can deliver about 14 KB in the first round trip, 28 KB in the second, 56 KB in the third. A 100 KB page therefore needs about four round trips just to ramp up, which on a 150 ms path is 600 ms regardless of bandwidth. That is why small responses are latency-bound, why keeping connections warm matters (an established connection has already grown its window), why CDNs terminate connections close to users, and why critical page resources are kept under the initial window.
Modern algorithms
| Algorithm | Signal | Behaviour | Where |
|---|---|---|---|
| Reno / NewReno | Loss | Halve on loss, grow one segment per RTT; slow to fill fast long links | Historical baseline |
| CUBIC | Loss | Window grows as a cubic function of time since the last loss, recovering quickly on high bandwidth-delay paths | Linux, Windows and macOS default |
| BBR | Measured bandwidth and minimum RTT | Models the path's bottleneck bandwidth and round-trip time and paces sending to match, rather than filling buffers until loss | Google services, many CDNs; opt-in on Linux |
| DCTCP and ECN-based | Explicit congestion marks from switches | Reacts to marks before loss occurs, keeping queues short | Data centres |
Bufferbloat
Loss-based algorithms keep increasing the window until a buffer overflows. If routers and modems have very large buffers, they fill first, so packets queue for hundreds of milliseconds before any loss occurs: throughput is fine but latency for everyone on that link balloons. That is bufferbloat, felt when a video call lags while someone uploads a backup. Fixes are active queue management on routers (CoDel, FQ-CoDel), explicit congestion notification so routers can signal before dropping, and model-based algorithms like BBR that avoid filling queues.
Fairness and its limits
Congestion control shares a bottleneck roughly equally per connection, not per user or application. A client that opens ten parallel connections gets about ten shares, which is why browsers capped connections per host and why download accelerators were fast. Mixing algorithms (BBR flows beside CUBIC flows) can also share unequally. Rate limiting and traffic shaping at the application or network level exist because transport fairness is a convention, not an enforcement mechanism.
Trade-offs
Loss-based control is robust and simple, at the cost of underusing fast long links, misreading wireless loss as congestion, and filling buffers. Model-based control keeps latency low and fills fat pipes, at the cost of complexity and fairness questions. Slow start protects the network from new connections at the cost of latency for short transfers, which pushes systems toward connection reuse and edge termination.
In an interview
Use it to explain why proximity and reuse beat bandwidth: "A 200 KB response to Sydney over a cold connection takes about five round trips of slow start, roughly 800 ms, even on a gigabit link. Terminating TLS at an edge node near the user and keeping warm, already-ramped connections from edge to origin cuts that to one or two short round trips plus a fast backbone transfer."
Check yourself
A team doubles their servers' bandwidth from 1 to 2 Gbit/s, but the time to download a 60 KB API response to distant users on fresh connections does not improve. Why?