Networking · 32 min read
Congestion Control
How endpoints detect a busy network and slow down so shared links do not collapse into congestive failure, including classic TCP dynamics and modern signal debates.
Why this exists
Packet networks do not reserve a private lane for every conversation. When senders are greedy, queues overflow, loss skyrockets, and useful throughput can collapse.
Congestion control is the distributed etiquette (and mechanism) that makes sharing work: detect stress, reduce sending rate, probe carefully for spare capacity.
Without it, the internet's shared fabric fails in a way that looks like 'the network is broken' even when every link is physically fine. The failure mode is overload, not absence of wire.
Axioms & primitives
- 01Congestion is overload of queues and links, not merely 'distance'.
- 02Loss and delay are signals; interpreting them correctly is hard on wireless and heavily buffered links.
- 03Fairness and utilization trade off; algorithms encode a policy, not a law of nature.
- 04TCP's historical algorithms made the internet scalable; newer schemes refine signals and fairness.
- 05Without congestion control, a fast sender can harm everyone including itself.
- 06Flow control is not congestion control: one protects a receiver host, the other protects the path.
Learning objectives
After this lesson you should be able to:
- Explain congestive collapse in plain language.
- Distinguish slow start from congestion avoidance at a conceptual level.
- Say why bufferbloat makes delay-based suffering worse even when throughput looks fine.
- Argue why a bare UDP video stream should still pace itself.
- Separate flow control symptoms from congestion control symptoms in a debugging story.
Progressive depth
Read the layers in order for a full explanation. Or open the layer you need.
Intuition
Imagine every download trying to blast at full NIC speed into a shared ISP uplink. Queues at the bottleneck explode. Packets drop. Everyone retransmits. The link carries mostly duplicates and collapses.
Congestion control is how polite (and mandatory) senders notice that pain and slow down before the shared resource fails for all.
Distance latency (speed of light) is not the same problem. You can have a long fat pipe that is empty, or a short pipe that is melting. Congestion is about overload.
Formal shape
Classical TCP: slow start grows the congestion window exponentially until a threshold or loss signal, then congestion avoidance grows it more gently (roughly linearly in classic AIMD stories). Multiplicative decrease on loss cuts the window.
Signals evolved: packet loss, ECN marks, delay gradients (e.g. BBR-style models of bottleneck bandwidth and RTT). Each signal can mislead: wireless loss is not always congestion; shallow buffers cause early loss; deep buffers hide loss behind delay.
Fairness is approximate. Many flows, slow flows, paced apps, and rate-limited video change outcomes. Active queue management (AQM) and fair queuing at bottlenecks complement end-host algorithms.
QUIC reimplements congestion control over UDP; HTTP/3 inherits those dynamics even though the on-wire protocol is not classical TCP.
Worked examples
A large file download ramps up, fills the pipe, reacts to loss or delay, and settles near capacity. Start a second download and both typically share.
A video call that ignores congestion will induce loss for itself and others; good RTC stacks adapt bitrate.
Bufferbloat lab: load a download on a home router and watch ping latency spike into hundreds of milliseconds. Throughput looks fine; interactive apps feel awful. AQM (fq_codel and friends) and better end-host CC both help.
Incast: many servers respond to one client at once in a datacenter; synchronized bursts overwhelm shallow buffers. Scheduling and specialized CC matter more than 'buy a bigger WAN'.
Edge cases
Latency-sensitive and bulk flows sharing a path need isolation (fq scheduling) as much as CC math.
Cellular networks reshape delay and loss patterns; algorithms tuned only on wired lab paths misbehave.
ECN deployment is uneven; falling back to loss signals remains common.
Turning off congestion control 'to go faster' often makes large transfers complete slower on a shared bottleneck because loss storms destroy goodput.
Mental models
Highway on-ramp lights
Meters cars onto a busy freeway so the freeway keeps flowing. Senders meter packets into the internet.
Room of people shouting
If everyone talks louder to be heard, nobody hears. Softening voices restores communication: reduce rate to restore useful throughput.
Probe and back off
Climb until you sense pain, then retreat, then climb again gently. Classic AIMD intuition.
Shared pantry
If every roommate grabs all snacks the moment they appear, nobody eats well. Congestion control is a pantry etiquette algorithm.
Common misconceptions
Myth
More buffering always fixes congestion.
Reality
Giant buffers turn loss into huge latency (bufferbloat). Interactive apps feel broken while the link is 'fully utilized'.
Myth
Congestion control is only a TCP detail I can ignore.
Reality
Any protocol that can saturate a path needs a policy. QUIC, RTC, and custom UDP apps inherit the same social problem.
Myth
The fastest machine should win all the bandwidth.
Reality
Uncontrolled competition destroys aggregate goodput. Endsystems are expected to share.
Myth
If I am not losing packets, there is no congestion.
Reality
Deep buffers can hide loss behind delay. Your ping spikes while downloads still 'succeed'.
Exercises
Work these without looking up answers first. Check yourself against the intent notes.
Exercise 01
A flow sees rising RTTs and then packet loss at a home router. What two different root causes might look similar in a naive 'loss = congestion' model?
What good looks like
True congestion vs wireless/error loss; also bufferbloat delaying then dropping.
Exercise 02
Why does "disable congestion control to go faster" often make a large transfer complete slower on a shared bottleneck?
What good looks like
Collapse/loss storms and unfairness reduce useful goodput; retransmissions waste capacity.
Exercise 03
Separate these: (a) receiver window stuck at a tiny value, (b) congestion window collapsing on loss. What layer of 'slow' is each?
What good looks like
a flow control / receiver or app not reading; b congestion control / path overload signals.
Sources & further reading
External references. Prefer primary documents and clear explainers.
- Packets, routing and reliability
high · 2017-maps
- An introduction to computer networks
high · 2017-maps
- RFC 5681 - TCP Congestion Control
high
Uncertainty notes
- Specific modern algorithms (CUBIC, BBR variants) evolve quickly; learn the problem and signals, then treat named variants as replaceable tactics.
Go deeper on your own
These picks go past the foundation in this lesson. Use them when you want a primary spec, official docs, or a longer walkthrough.
Classic Reno-style TCP congestion algorithms. Use it when you need slow start and congestion avoidance rules.
CUBIC, the default congestion control on many systems today. Read it after you understand loss-based windows.
Textbook walkthrough of Tahoe and Reno control loops. Good when RFCs feel too dense at first.