FQ是Linux网络栈中用于本地发包流量整形的无类别qdisc,仅作用于本机发出的报文,通过流隔离、credit轮询和高优先级FIFO队列实现公平调度,需配合TCP pacing与合理参数调优才能生效。

Linux 网络栈的“公平调度”不是靠一个开关就能打开的,它取决于你指哪一层:是本地发包的流量整形(FQ),还是块设备 I/O 的调度(CFQ),抑或是 CPU 任务调度(CFS)。三者名字都带“公平”,但完全不互通、不兼容。搞错层级,tc qdisc add 命令再熟也没用。
确认你要配的是发包层的 FQ(Fair Queueing)
这是最常被问到、也最容易配错的一层。FQ 是内核网络栈中用于控制本地生成报文发送节奏的无类别 qdisc,只作用于本机发出的流量(比如你的服务端回包、curl 请求发出的包),不处理转发或接收流量。
- 错误现象:
tc qdisc show dev eth0显示fq,但压测时小流依然被大流饿死 —— 很可能你没关 TCP pacing 或没调flow_limit,FQ 默认按流隔离,但单个流内部仍可能突发 - 典型命令:
sudo tc qdisc add dev eth0 root fq,必须指定root,不能加parent(FQ 不支持分层) - 关键参数要手动调:
limit控制总队列长度(默认 10000 包,内存吃紧时建议降到 2000),flow_limit控制单流最多缓存多少包(默认 100,对短连接多的场景易丢包,可设为 50) - 别碰
quantum:默认是 2×MTU(如 3028),改大了会让小流等待更久;改小了会增加调度开销,一般不动
别把 CFQ(I/O 调度器)和 FQ 混一起
CFQ 是块设备层的 I/O 调度器,名字虽像,但它管的是磁盘读写请求的排队顺序,和网络发包毫无关系。你在 /sys/block/sda/queue/scheduler 里看到 cfq,和 tc qdisc 输出的 fq 是两套完全独立的机制。
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 常见误操作:看到文档说“CFQ 提供公平 I/O”,就以为能改善网络延迟 —— 实际上网络延迟主要卡在协议栈、网卡驱动、中断处理,跟磁盘调度无关
- SSD 上禁用 CFQ:现代 SSD 不需要寻道优化,
echo kyber > /sys/block/nvme0n1/queue/scheduler更合适;强行留 CFQ 反而因slice_idle引入无谓延迟 -
ionice只影响进程级 I/O 优先级,对网络 socket 发包速率零影响
应用层怎么配合 FQ 才真有效
FQ 要发挥效果,得和 TCP 栈协同。单纯加 qdisc 不够,应用若不启用 pacing,FQ 就只能被动丢包;若 pacing 设太高,FQ 的 credit 机制就形同虚设。
- 必须开启 TCP pacing:
echo 1 > /proc/sys/net/ipv4/tcp_pacing_loss_train(内核 ≥ 5.10),否则 FQ 对丢包恢复无效 - 限制单 socket 发送速率:
setsockopt(fd, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)),rate 单位是 byte/s;不设的话,FQ 会按流均分带宽,但大流仍可能占满 credit - 注意
low_rate_threshold:默认 550Kbit/s,低于此值的流会被跳过 credit 计算,直接插队——这对小包 ACK 很友好,但若你有大量低速 IoT 连接,可能需调低该值
FQ 的公平性是动态且脆弱的:它依赖每个流的哈希一致性、credit refill 的定时精度、以及应用是否主动限速。一旦某流持续打满 credit,其他流就会被压制——这不是 bug,是设计使然。真正要保小流,得靠 flow_limit + 应用层 pacing + 合理的 refill_delay 组合,而不是指望一个 qdisc 自动搞定所有场景。

















