Linux流控队列深度对比:fq、fq_codel与CAKE源码机理与选型

测试环境:本文实测数据来自 DMIT 的 VPS。

很多朋友给 VPS 开启 BBR 甚至 BBRplus 之后,会发现一个普遍现象:测速跑单线程带宽似乎上去了,但实际看 4K 视频、打游戏或者开网页时依然有明显的卡顿感,尤其是晚高峰丢包率上升时更为严重。

这背后的根本原因在于:你只调整了“拥塞控制算法(Congestion Control)”,却没有配置好底层的“排队规则(qdisc / Queueing Discipline)”。

在我们的横评指南 《Linux拥塞控制与内核源码级横评:BBR、BBRplus与第三方内核》 中曾提到,拥塞控制决定的是“什么时候发、发多快”,而排队规则(fq / fq_codel / CAKE)决定的是“当数据堆积在网卡缓冲区时,先丢谁的包、按什么顺序发包”。本文从 Linux 内核源码实现剖析三大主流队列规则,并提供选型参考。


快速选型速查表

在深入源码之前,先看三者的横向对比结论:

队列规则 (qdisc) 核心算法与机制 资源消耗 抗 Bufferbloat(缓冲区膨胀)能力 最佳应用场景
fq (Fair Queue) 基于 Socket 的公平队列 + 精确 Pacing 时钟整形 极低 (单核首选) 中等(依赖拥塞算法主动限速) 纯拉大文件下载、单核 512M 小鸡、原生 BBR 标配
fq_codel CoDel 主动队列管理 (AQM) + 1024 桶流隔离 中等 优秀(排队延迟超过阈值主动丢包) Debian/Ubuntu 通用服务器默认、常规建站
CAKE 8-way 组合哈希 + DiffServ 优先级队列 + ACK 压缩反压 稍高(CPU 开销略高于 fq_codel) 顶级 (满载延迟基本不抖动) XanMod 内核用户、多核 VPS、晚高峰跨国弱网、兼顾游戏与测速

一、 源码级原理解析:三大队列是怎么工作的?

1. fq (net/sched/sch_fq.c):为 Pacing 而生

在 Linux 内核源码树中,sch_fq.c 的核心结构极其简洁。它本质上不是为了复杂调度而设计的,而是 Google 为了配合 BBR 的节奏发包(Pacing)而专门定制的。

1
2
3
4
5
6
7
8
9
/* net/sched/sch_fq.c 源码核心结构片段 */
struct fq_flow {
struct rb_node fq_node; /* 挂在红黑树上的流节点 */
struct sk_buff *head; /* 数据包链表头 */
struct sk_buff *tail; /* 数据包链表尾 */
u32 credit; /* 流量积分 */
u64 time_next_packet; /* 下一个包允许发送的时间戳 */
...
};

工作机理:

  • Pacing 时钟约束:当 BBR 算法计算出当前的瓶颈带宽后,会给每个 sk_buff 打上时间戳。fq 并不直接一股脑把包推给网卡驱动,而是将其放入红黑树中,只有当当前系统时间 >= time_next_packet 时才允许出队。
  • 优点:彻底消除了突发大流量(Burst)将交换机和中间路由器缓存瞬间打爆的情况。
  • 缺点:它只管节奏,对“突发排队”没有主动防御机制。如果你遇到了开启调优后依然测速异常的情况,建议对照 《BBR 开启后没有速度提升?排查这 5 个关键原因》 逐步排查 NAT 或硬件队列配置。

2. fq_codel (net/sched/sch_fq_codel.c):智能丢包与小包插队

fq_codel 是当代 Linux 系统的通用标准。它将 Fair Queueing(公平队列)与 CoDel(Controlled Delay,受控延迟)结合在一起。

核心源码逻辑:

  1. 区分肥流与瘦流(Fat vs Sparse Flows):
    • 像视频流、大文件下载这种持续占满带宽的叫做“肥流”;
    • 像 SSH 击键、DNS 查询、TCP 握手包这种偶尔发一个包的叫做“瘦流”。
    • fq_codel 会无条件优先清空“瘦流”队列,这也是为什么开启 fq_codel 时,后台满速下载你敲 SSH 也不会感觉卡顿的原因。
  2. CoDel 驻留时间检测:
    • 源码跟踪每个数据包在队列里的排队时间。如果排队持续时间超过 target(默认 5ms),CoDel 会判定主机遭遇了 Bufferbloat,立即开始按丢包状态机进行主动丢弃(Drop),强迫客户端 TCP 降速。

3. CAKE (net/sched/sch_cake.c):流控终极解决方案

CAKE(Common Applications Kept Enhanced)由网络专家开发并合并入 Linux 主线内核,是当前抗弱网抖动最强力的利器。

相比 fq_codel 的三大源码级升级:

  1. 8-way Set Associative Hash(8路组相联哈希):
    • 普通 fq_codel 遇到大量并发连接时,不同连接可能由于哈希冲突被分到同一个桶里;CAKE 借鉴了 CPU 缓存算法,通过 8 路组合哈希将冲突概率降低了数个数量级。
  2. DiffServ 自动分级调度(Tin 架构):
    • 源码内置了 3 级(Bulk 批量、Best Effort 普通、Voice/Interactive 实时语音交互)优先级“锡罐(Tins)”。低延迟数据包自动插队,且各级之间按权重平滑分配,绝不饿死低优先级流量。如果希望用上 CAKE,可以参考 《一键更换为 XanMod 内核实战》 部署新版内核,再手动设置 net.core.default_qdisc=cake 开启(XanMod 默认拥塞算法是 BBRv3,队列规则需手动指定)。
  3. ACK 过滤(ACK Filtering):
    • 在高并发上传时,大量冗余的反向 ACK 包会抢占上行带宽;CAKE 会在队列中自动合并丢弃旧的累积 ACK,释放珍贵的上行信道。

二、 场景选型指南

场景 1:512MB / 1GB 单核低配 VPS

  • 推荐组合:fq + BBR
  • 理由:CAKE 在极高带宽突发时会占用更多的软中断(SoftIRQ)开销。单核低配小鸡建议保持最精简的 fq,不给 CPU 增加计算负担。

场景 2:跨国晚高峰代理、中转落地机、多核 VPS

  • 推荐组合:CAKE + BBR
  • 理由:晚高峰公网丢包率明显上升时,单纯靠重传会造成雪崩式队列阻塞。CAKE 能够精准保住握手包与关键信令包,平滑弱网延迟。若需定位跨国骨干网在哪个跳数发生了严重拥塞,可直接通过 《NextTrace教程:开源可视化路由追踪》 实时追踪路径质量。

三、 实操:如何在 VPS 上切换并验证?

步骤 1:检查当前生效的队列与拥塞控制

1
2
3
4
5
# 查看当前网络接口生效的队列规则
tc qdisc show dev $(ip route show default | awk '{print $5}')

# 查看当前的 TCP 拥塞控制算法
sysctl net.ipv4.tcp_congestion_control

步骤 2:切换为 CAKE + BBR

在 Debian 11+ / Ubuntu 20.04+ 或安装了定制内核的系统上,直接写入 sysctl 配置:

1
2
3
4
5
6
7
8
9
10
sudo tee /etc/sysctl.d/99-network-qdisc.conf << 'EOF'
# 设置默认排队规则为 cake
net.core.default_qdisc = cake

# 设置拥塞控制算法为 bbr
net.ipv4.tcp_congestion_control = bbr
EOF

# 加载配置
sudo sysctl --system

如果在调优和管理多服务 VPS 期间遇到了端口枯竭、进程假死等深层异常,可以随时查阅我们的 《Linux网络与VPS日常运维故障全景排查手册》 快速定位问题。