{"id":1516,"date":"2026-10-26T22:42:38","date_gmt":"2026-10-26T22:42:38","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=1516"},"modified":"2026-10-26T22:42:38","modified_gmt":"2026-10-26T22:42:38","slug":"bbr-fq-vs-cake-fq-codel-single-vcpu-triage","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/","title":{"rendered":"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS"},"content":{"rendered":"<div style=\"padding:20px\">\n<p>Everyone has already enabled BBR. The question on a single-vCPU box is not which congestion control to use, it is what you pair it with \u2014 BBR plus fq, or the fq_codel queueing that CAKE builds on. Both work; they fail differently under saturation, and the CPU cost is not the same when you only have one core. This is a measurement methodology you can run on a $10 instance in about forty minutes, with the specific counters to read. Whether your provider&#8217;s kernel exposes the needed qdiscs is a separate question worth checking in the <a href=\"https:\/\/virtualserversvps.com\/\">VPS provider list supporting modern kernels<\/a>.<\/p>\n<h2>Why the Pairing Matters More Than BBR<\/h2>\n<p>BBR is a congestion control algorithm: it decides send rate. fq and CAKE are queue disciplines: they decide what happens to packets waiting to leave the interface. BBR estimates bottleneck bandwidth and round-trip time and paces packets to match. That pacing assumes a queue discipline that spreads packets out rather than dumping bursts \u2014 which is why the canonical pairing is BBR + fq. CAKE does the same spreading plus per-host fairness and optional shaping, but it computes a shaper and a hash per flow, and on one vCPU that computation competes with your application.<\/p>\n<pre><code>sysctl -n net.ipv4.tcp_congestion_control\nsysctl -n net.core.default_qdisc\ntc qdisc show dev eth0<\/code><\/pre>\n<p>Expected on a stock Ubuntu 24.04 kernel: <code>cubic<\/code>, <code>fq_codel<\/code>, and <code>qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms<\/code>. If you see <code>noqueue<\/code>, the interface is a virtual NIC that hands packets straight to the hypervisor and qdisc changes will have limited effect \u2014 check that before benchmarking anything.<\/p>\n<h2>The Two Stacks, Precisely<\/h2>\n<pre><code># Stack A: BBR + fq\nsysctl -w net.core.default_qdisc=fq\nsysctl -w net.ipv4.tcp_congestion_control=bbr\ntc qdisc replace dev eth0 root fq maxrate 900mbit\n\n# Stack B: CAKE + fq_codel leaves (CAKE's internal default)\nsysctl -w net.core.default_qdisc=fq_codel\nsysctl -w net.ipv4.tcp_congestion_control=bbr\ntc qdisc replace dev eth0 root cake bandwidth 900mbit diffserv4<\/code><\/pre>\n<p>Two details people skip. First, <code>maxrate<\/code> on fq is what makes BBR pace properly; without it fq spreads packets but doesn&#8217;t shape, and you lose the pacing benefit at rates above the link. Second, CAKE&#8217;s <code>bandwidth<\/code> must be set below the real link rate \u2014 900 Mbit on a 1 Gbit port \u2014 or the shaper never engages and CAKE behaves like a more expensive fq_codel. If you set the bandwidth above the physical rate, you are measuring nothing.<\/p>\n<h2>What to Measure, and With What<\/h2>\n<p>CPU cost, latency under load, retransmits, and throughput \u2014 in that order of importance on a single vCPU. A stack that gains 5% throughput and costs 20% CPU is a net loss when that CPU runs your web server.<\/p>\n<pre><code># CPU cost of the qdisc itself, excluding the app\npidstat -u 1 30 | awk '\/%CPU\/ || \/ksoftirqd|kworker\/'\n\n# Per-socket state during the test\nss -tin dst TARGET_IP | grep -E 'bbr|cwnd|rtt|retrans|snd'\n\n# Retransmit and loss counters\nnstat -az TcpRetransSegs TcpOutSegs TcpExtTCPLostRetransmit<\/code><\/pre>\n<p>The <code>ss -tin<\/code> output is where the useful signal lives. On BBR you will see <code>bbr<\/code> in the algorithm field along with <code>bw:<\/code> and <code>mrtt:<\/code> estimates. <code>rcv_ssthresh<\/code> shows how much receive window the kernel is willing to open \u2014 if it&#8217;s pinned low, you&#8217;re being limited by the receiver or by an undersized socket buffer, not by the congestion control, and the whole A\/B test is measuring the wrong thing.<\/p>\n<h2>Test 1: Bufferbloat Under Saturation<\/h2>\n<p>Generate a saturating upload from one client while pinging a third host, and look at RTT inflation rather than average throughput.<\/p>\n<pre><code># Terminal 1: saturate the uplink\niperf3 -c TARGET -t 60 -P 4\n\n# Terminal 2: latency under load, 100 pings at 200ms\nping -i 0.2 -c 300 OTHER_HOST | tail -3<\/code><\/pre>\n<p>Baseline idle RTT to the third host: 14 ms. Under load with <code>fq_codel<\/code> and no shaping, expect 60\u2013180 ms and jitter \u2014 the classic bufferbloat signature, because the qdisc has no target rate to pace against. With BBR + <code>fq maxrate 900mbit<\/code>, RTT under load typically lands at 16\u201328 ms. With CAKE at 900 Mbit, 16\u201324 ms with noticeably tighter jitter. The difference between A and B here is usually small; the difference between either and leaving the default <code>fq_codel<\/code> is large. That comparison is the one worth running first.<\/p>\n<h2>Test 2: Retransmits and Loss Recovery<\/h2>\n<pre><code>nstat -n &gt; \/dev\/null            # reset counters\niperf3 -c TARGET -t 60 -P 4\nnstat TcpRetransSegs TcpOutSegs TcpExtTCPLostRetransmit\nawk '\/TcpRetransSegs|TcpOutSegs\/ {print $2, $3}' \/proc\/net\/netstat<\/code><\/pre>\n<p>Compute the ratio, not the absolute count: <code>TcpRetransSegs \/ TcpOutSegs<\/code>. Under 0.1% is clean. Between 0.1% and 1% suggests a lossy path. Above 1% and BBR is doing its job anyway \u2014 it reacts to delivery rate rather than loss \u2014 but your users see stalls. If CAKE shows materially lower retransmits at the same throughput, the shaper is smoothing bursts that were overflowing a downstream buffer. If the numbers are identical, the downstream bottleneck is elsewhere and the qdisc choice is not your problem.<\/p>\n<h2>Test 3: CPU Cost on One vCPU<\/h2>\n<p>Run the same 60-second iperf3 three times per stack and record <code>ksoftirqd<\/code> plus total system CPU from <code>pidstat<\/code>. On a single vCPU with one 1 Gbps flow, the realistic numbers are: <code>fq<\/code> at roughly 3\u20136% of the core, <code>cake<\/code> at roughly 12\u201322% with <code>diffserv4<\/code>. CAKE&#8217;s per-packet hashing, DSCP classification and shaper token accounting cost real cycles, and those cycles come out of the same core running nginx.<\/p>\n<pre><code># Isolate: one stream, then ten\nfor p in 1 4 10; do\n  iperf3 -c TARGET -t 30 -P $p --json | jq \".end.sum_sent.bits_per_second\/1e6\"\ndone<\/code><\/pre>\n<p>Watch how the CPU gap scales with stream count. fq&#8217;s cost is close to flat \u2014 more flows just means more hash buckets. CAKE&#8217;s rises because per-flow classification continues and the shaper does more work per second at higher packet rates. Past roughly 8,000 pps of sustained traffic on one vCPU, CAKE becomes a visible fraction of your headroom.<\/p>\n<h2>When Each Wins<\/h2>\n<table>\n<thead>\n<tr>\n<th>Situation<\/th>\n<th>Preference<\/th>\n<th>Reason<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Web server, 1 vCPU, &lt;2k pps<\/td>\n<td>BBR + fq<\/td>\n<td>Lowest CPU cost, pacing intact<\/td>\n<\/tr>\n<tr>\n<td>Shared host with bursty neighbours<\/td>\n<td>CAKE + shaping<\/td>\n<td>Per-host fairness caps your own bursts<\/td>\n<\/tr>\n<tr>\n<td>Uplink smaller than LAN (50\/100 Mbit)<\/td>\n<td>CAKE at 95% link rate<\/td>\n<td>Shaping prevents upstream bufferbloat<\/td>\n<\/tr>\n<tr>\n<td>Max throughput, CPU-bound app<\/td>\n<td>BBR + fq maxrate<\/td>\n<td>CAKE&#8217;s shaper spends cycles you need<\/td>\n<\/tr>\n<tr>\n<td>Many tenants behind one NIC<\/td>\n<td>CAKE diffserv4<\/td>\n<td>Priority classes without tc filters<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Pitfalls That Invalidate the Test<\/h2>\n<ul>\n<li><strong>Changing both variables at once.<\/strong> Congestion control and qdisc must be varied independently, or you can&#8217;t attribute the result.<\/li>\n<li><strong>Benchmarking over Wi-Fi or a shared laptop uplink.<\/strong> Your client&#8217;s own buffer dominates the RTT measurement.<\/li>\n<li><strong>Forgetting <code>tc qdisc replace<\/code> vs <code>add<\/code>.<\/strong> <code>add<\/code> stacks a second qdisc and you measure the wrong one.<\/li>\n<li><strong>Not resetting counters between runs<\/strong> \u2014 <code>nstat<\/code> accumulates and the retransmit ratio drifts.<\/li>\n<li><strong>Testing at 900 Mbit on a 100 Mbit plan.<\/strong> The shaper never engages and every result is noise.<\/li>\n<\/ul>\n<p>Write the per-run numbers into a file and keep them. Kernel versions change CAKE&#8217;s defaults and BBR&#8217;s pacing behaviour between releases, and a result from 6.5 is not a result on 6.8. Re-run the three tests when you upgrade the box or move providers \u2014 the pair that wins on a 1 Gbps port with 20 ms of headroom is not necessarily the pair that wins on a 200 Mbit port. If you&#8217;re starting from a fresh instance, the <a href=\"https:\/\/virtualserversvps.com\/\">VPS plans with root-level tc access<\/a> are the ones where any of this is testable at all.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Everyone has already enabled BBR. The question on a single-vCPU box is not which congestion control to use, it is what you pair it with \u2014 BBR plus fq, or&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1516","post","type-post","status-publish","format-standard","hentry","category-performance-optimization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS - Virtual Servers VPS Blog<\/title>\n<meta name=\"description\" content=\"Everyone has already enabled BBR. The question on a single-vCPU box is not which congestion control to use, it is what you pair it with \u2014 BBR plus fq, or\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS\" \/>\n<meta property=\"og:description\" content=\"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-26T22:42:38+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/\",\"name\":\"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-10-26T22:42:38+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"description\":\"Everyone has already enabled BBR. The question on a single-vCPU box is not which congestion control to use, it is what you pair it with \u2014 BBR plus fq, or\",\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS - Virtual Servers VPS Blog","description":"Everyone has already enabled BBR. The question on a single-vCPU box is not which congestion control to use, it is what you pair it with \u2014 BBR plus fq, or","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/","og_locale":"en_US","og_type":"article","og_title":"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS","og_description":"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS","og_url":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-10-26T22:42:38+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/","url":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/","name":"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-10-26T22:42:38+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"description":"Everyone has already enabled BBR. The question on a single-vCPU box is not which congestion control to use, it is what you pair it with \u2014 BBR plus fq, or","breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/bbr-fq-vs-cake-fq-codel-single-vcpu-triage\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"BBR + fq vs CAKE + fq_codel: Picking a Queue Discipline on a Single-vCPU VPS"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1516","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=1516"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1516\/revisions"}],"predecessor-version":[{"id":1519,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1516\/revisions\/1519"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=1516"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=1516"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=1516"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}