Skip to content
Congestion Control
step 1/5

Reading — step 1 of 5

Read

~2 min readProduction Concerns

Congestion Control

Flow control answers "will the receiver keep up?" Congestion control answers a harder question: "will the network keep up?" They are different limits, and TCP obeys both at once — it may send only the smaller of the receiver's advertised window and its own congestion window (cwnd), an estimate of what the path itself can carry.

Why does the network need protecting? In 1986 the early Internet suffered congestion collapse: every sender pushed as hard as it could, routers dropped the overflow, everyone retransmitted the drops, and useful throughput fell by a thousandfold. Congestion control is the fix, and it is why the Internet does not melt under load today.

The two phases

cwnd is not advertised by anyone — each sender infers it from how its segments fare, growing while ACKs flow and shrinking on loss:

Rendering diagram…
  • Slow start — despite the name, cwnd grows exponentially: roughly doubling every RTT (one extra MSS per ACK). This probes the path's capacity quickly. It runs until cwnd reaches a threshold, ssthresh.
  • Congestion avoidance — past ssthresh, growth turns linear: about one MSS per RTT. This is the cautious "additive increase" of AIMD (Additive Increase, Multiplicative Decrease).

On loss, TCP backs off. Three duplicate ACKs — a mild signal, since data is still arriving — roughly halve cwnd and enter fast recovery. A full timeout — a severe signal, since the pipe went silent — resets cwnd to one MSS and restarts slow start. Punishing timeouts harder than dup-ACKs is the core instinct of every loss-based algorithm.

The algorithms you will hear named

  • Reno — the 1990s baseline: slow start, AIMD, fast retransmit/recovery. Simple, and still the reference model.
  • CUBIC — Linux's default for years; cwnd follows a cubic curve of time since the last loss, recovering faster on high bandwidth-delay links.
  • BBR (Google, 2016) — ignores loss as the signal and instead models the path's bandwidth and minimum RTT directly, setting the rate near the bandwidth-delay product. It shines on lossy mobile links and fights bufferbloat.

The trap

cwnd and the receiver's rcv_wnd are independent limits; the amount you may have in flight is min(cwnd, rcv_wnd), and a common mistake is tracking only one. Note the payoff of getting this right: effective throughput is cwnd / RTT, so on a 50 ms path a 64 KB window yields only ~1.3 MB/s — reaching gigabit needs megabyte-scale windows, which is exactly why window scaling and congestion control have to work together.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…