The Runtime Theory
mediumApplicationDSA#networking#tcp#congestion-control

Why is TCP slow to start and how does congestion control fix it?

Tests whether you understand the difference between flow control and congestion control, and why TCP deliberately wastes capacity to discover the network.

The Runtime Theory Team2 min readasked at netflix · google · meta · spotify

This question separates people who think TCP "just works" from people who know it's a sender-side feedback loop. The core idea: the sender doesn't know how much capacity the path has, so it guesses — and the guess has to be cheap to recover from.

The mental model: two windows, two different problems.

Flow control is local: the receiver's advertised window (rwnd) says "I can buffer this much." Congestion control is global: the cwnd says "the network can carry this much" — and that number is invisible. Nobody on the path tells you it. So TCP must probe.

Slow start is that probe. The sender starts with a tiny cwnd — historically one segment (1460 bytes), today often 10 segments on Linux. Each ACK received doubles the window, so cwnd grows exponentially: 1, 2, 4, 8 segments per RTT. From zero, a 100MB download over a 20ms RTT needs about 14 RTTs (~280ms) to reach a multi-gigabit rate. That exponential ramp is why TCP is "slow to start" in absolute terms — the first few RTTs move almost nothing — yet it's actually the fastest safe way to find capacity.

The sender keeps growing until one of three things happens: it hits ssthresh and switches to linear growth (congestion avoidance, +1 segment per RTT), it hits the receiver's rwnd, or — the interesting case — a loss occurs. On loss, classic Reno halves cwnd and re-enters slow start below the new ssthresh. In the trace, you can see the sawtooth: exponential climb, loss, halving, climb again.

Why the deliberate waste? If you started at full speed, you'd dump tens of MB into a network that can carry tens of KB — the drop rate would explode and retransmissions would eat the gain. Starting small means the worst case is a handful of lost packets while probing, not a collapsed link. The ACK clock is the discovery mechanism: ACKs tell you both that data got through and implicitly, by their pacing, how fast the path drains.

Tradeoffs and edge cases: loss-based control is blind on high-bandwidth-delay-product paths — one drop on a 100ms RTT link can tank a video stream. That's why BBR measures pacing and RTT directly instead of waiting for loss, and why short transfers never leave slow start — a 10KB API response is done before the window has grown to even 64KB.

This answer walks

Follow-ups they'll push on

  1. 01What's the difference between slow start and congestion avoidance?
  2. 02How does BBR decide a safe sending rate?
  3. 03What happens to throughput when a single packet is lost?

More interviews in this topic

One dispatch a week

The trace behind each question, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.