Slowyslowyapp.com

03 Bufferbloat

Fairness between flows

One heavy transfer should not be able to starve everything else, and whether it can depends on how the queue is organised.

Entry 04 of 04Where the delay actually comes from.All of Bufferbloat

Several parallel cable runs of different colours entering a switch
Parallel runs into one switch: several flows, one departure point, one decision about order.slowyapp.com picture kit

One queue, many conversations

Every packet that leaves a network interface passes through a queue. On a simple FIFO queue — first in, first out — packets are forwarded in arrival order without any regard for which application or connection they came from. That arrangement works fine when traffic is sparse. When the link is busy, it hands control to whoever is sending the most: a large file transfer stuffs the queue with its own packets, and the queue obeys, leaving a VoIP call or a DNS lookup to wait in line behind hundreds of kilobytes it has nothing to do with.

The formal name for this problem is flow starvation. A flow is a single conversation identified by its source and destination addresses and port numbers — one TCP connection, one UDP stream. FIFO gives no weight to how many flows are competing or how demanding each one is. The heavy transfer does not intend to harm the others; it simply fills the available space, and the queue obliges.

What organised queues do differently

The response, developed across several decades of research, is to maintain separate queues per flow and then schedule service across them. The oldest complete formulation is Weighted Fair Queuing, described in work published in the late 1980s and early 1990s. The intuition is simple: if there are four active flows and one of them is a bulk transfer, the scheduler still gives each flow a proportional share of departure slots. The bulk transfer cannot consume more than its share; the small flows are not starved.

A long queue of identical objects on a conveyor in a plain industrial setting
A line of identical objects waiting for a narrow exit is the whole mechanism.slowyapp.com picture kit

Real implementations approximate this ideal. Stochastic Fair Queuing, and later Stochastic Fair Blue and the family of algorithms that came after, use hash functions to assign packets to buckets without maintaining per-flow state explicitly — a practical compromise that scales to high link rates. The Linux kernel's fq_codel, built on the CoDel algorithm of Kathleen Nichols and Van Jacobson, and developed by Eric Dumazet, Dave Taht and others associated with Bufferbloat.net, combines per-flow queuing with the CoDel active queue management algorithm. It tracks flows by hash, isolates sparse flows from bulk ones, and applies early drop signals to senders that are building up queue depth.

The key insight behind that design is that sparse flows — the VoIP call, the keypress in an SSH session — are self-limiting. They generate a packet, wait for a response, and go quiet. A fair scheduler can identify these flows by the fact that their queue rarely contains more than one or two packets, and it can privilege them without explicit configuration. The bulk transfer, by contrast, continuously refills its bucket; the scheduler recognises that pattern and rates it accordingly.

Why it matters for conditioning

When you are deliberately degrading a connection to test how software behaves, fairness between flows is not usually the first parameter you reach for. Bandwidth, added latency, and packet loss are more obvious controls. But in any realistic test involving more than one concurrent connection — a background sync running while a foreground request is measured, for example — the queue discipline underneath determines whether those connections interact at all. A FIFO queue on a constrained link collapses that test into an artefact: one flow wins, the rest wait, and the numbers reflect queue position rather than application behaviour.

A shaper that uses a fair-queuing discipline isolates flows from each other even when the link is saturated. Repeatability follows from that isolation: each run produces the same competition among flows because the scheduler enforces the same sharing policy. Without it, which flow happens to arrive first — a timing accident — determines the outcome, and the test cannot be reproduced.

This is why the congestion-control literature, running from Van Jacobson's 1988 paper through the subsequent decades of IETF and ACM SIGCOMM work, returns so consistently to scheduling. Throughput is the headline number; fairness is the structural property that makes shared links actually usable.

A screen showing a latency graph with a sharp drop after a change
The drop after a change is the signal arriving early enough to be useful.slowyapp.com picture kit