Fixing Bufferbloat on a VPS: fq_codel and CAKE Queue Disciplines Explained and Measured

You can tune TCP congestion control all day and still see latency spiral during a backup or a large upload, because the culprit is not the congestion-control algorithm — it is the queue in front of your network interface. When a link is saturated, any packet that cannot be transmitted immediately waits in a buffer, and that buffer can grow to hundreds of milliseconds of standing queue. This phenomenon is bufferbloat, and on a VPS it is fixable with a different queueing discipline. This article explains how to swap the default pfifo_fast for an active queue management (AQM) qdisc and measure the difference.

Why the Default Queue Causes Latency

The default pfifo_fast qdisc is a simple FIFO with priority bands. It does not drop packets early or signal the sender to slow down until the buffer is completely full — and by then every packet in the queue, including your latency-sensitive interactive traffic, is waiting behind a bulk transfer. The result is that ping times can jump from 5 ms to 300 ms the moment a backup starts, even though average throughput looks fine. Absorbing that queue depth is exactly the wrong thing for interactive workloads; a small amount of early dropping preserves responsiveness.

Inspect the Current Setup

ip -s link show dev eth0 | head -20
qdisc show dev eth0
tc -s qdisc show dev eth0

Note the interface name, the MTU, and which qdisc is currently attached. On a virtualised host the interface is usually a virtio or emulated device; the qdisc you configure applies to the transmit path in the guest kernel. Some hypervisors also impose their own shaping, so measure before and after rather than assuming.

Enabling fq_codel or CAKE

Two AQM qdiscs are worth using. fq_codel is in the mainline kernel, needs no tuning, and dramatically reduces standing queue by marking or dropping packets slightly before the buffer overflows. CAKE builds on it with built-in fairness between flows and optional bandwidth shaping, at a modest CPU cost — meaningful on a single-vCPU instance under heavy packet rates. Start with fq_codel:

tc qdisc replace dev eth0 root fq_codel
sysctl -w net.core.default_qdisc=fq_codel
tc -s qdisc show dev eth0 | head -3

Make it survive a reboot by adding net.core.default_qdisc = fq_codel to /etc/sysctl.d/. Note that default_qdisc only takes effect for newly created interfaces, so the tc command is still needed for the running one — or place a systemd unit that runs it at boot. If you prefer CAKE with fairness, use tc qdisc replace dev eth0 root cake bandwidth 950mbit, sizing the bandwidth slightly below the real link rate so CAKE owns the queue instead of the upstream device.

Measuring the Improvement

The test that matters is latency under load, not idle ping. Saturate the link and simultaneously measure round-trip time:

# Terminal 1: saturate upload
curl -T /dev/zero https://speed.example/upload -o /dev/null &
# Terminal 2: measure latency during saturation
ping -i 0.2 -c 50 1.1.1.1 | tail -3

With pfifo_fast you will typically see large jitter and a p95 latency in the tens or hundreds of milliseconds. With fq_codel or CAKE the same test should keep latency within a few milliseconds of idle. Run the comparison at least twice; the first run is often distorted by the curl process warming up. The tc -s output also reports dropped and marked packets — a healthy AQM shows some marks under saturation, which is the mechanism doing its job.

Where This Fits With Congestion Control

AQM and congestion control are complementary, not alternatives. An algorithm like BBR manages how aggressively you send; fq_codel manages what happens to packets already queued on your transmit path, including traffic you do not control. Running both gives the best result on a self-managed instance. For a wider view of the kernel settings that affect network behaviour, the VPS performance guides cover the sysctl knobs that pair with this; and if you are choosing an instance for latency-sensitive work, the hosting comparison pages explain how throughput and CPU are allocated.

Bufferbloat is invisible in throughput graphs and obvious to anyone waiting on a page load. Swapping to an AQM qdisc takes one command and five minutes of measurement — one of the highest-return network changes you can make on a VPS.

Leave a Reply