fq 和 fq_codel 在多租户带宽隔离中经常失效,因其设计目标是抗 bufferbloat 和提升单主机多连接公平性,而非租户级硬限;它们统一哈希所有流、无 per-tenant 速率控制、无法绑定 cgroup 或 namespace,且 drop 策略对短连接租户不公。

fq 和 fq_codel 在多租户带宽隔离中为什么经常“失效”
它们不是为严格租户隔离设计的——fq 和 fq_codel 的核心目标是抗 bufferbloat 和提升单主机上多连接的公平性,而非跨用户/租户的带宽硬限。当多个租户共享同一台宿主机、且流量都经由同一个 qdisc 实例出向时,它们会把所有流(不管属于哪个 uid、cgroup 或 namespace)统一哈希进几百个队列,再按流粒度轮询调度。这意味着:
- 一个租户发起 100 个 TCP 流,另一个只发 2 个,前者天然拿到约 50 倍的调度机会
- 没有 per-tenant 的 rate limit 或 weight 配置入口,无法绑定 cgroup v2 或 net_cls classid
- 如果租户间存在长连接 + 短突发混合场景,
fq_codel的 drop 策略可能优先惩罚短连接租户(因其 queue 建立晚、CE 标记滞后)
cake 能否直接用于租户级限速
不能直接替代 tc htb + filter 组合,但比 fq/fq_codel 更接近可用:它内置了 nat 和 diffserv4 模式,能基于五元组 + DSCP 分类,并支持 per-flow 速率平滑。不过关键限制在于:
-
cake的bandwidth参数是全局总带宽上限,不支持 per-class 或 per-filter 的子速率配置 - 它识别 NAT 后的客户端 IP(需开启
nat),但无法感知容器 network namespace 或 pod UID —— 仍需配合tc filter+flowid把不同租户流量打上不同 classid - 在高并发小包场景(如微服务 mesh),
cake的内部分类开销比htb高约 15%~20%,实测 p99 延迟抖动更明显
真正可行的多租户带宽控制组合方案
必须分层:用 htb 做租户级硬限,用 fq_codel 或 cake 做租户内流控。典型链路是:root qdisc = htb → 每个租户对应一个 htb class → 在每个 class 下挂 fq_codel(或 cake)作为 leaf qdisc。
- 租户标识靠
tc filter+match ip src/ip dst或cgroup(需内核 ≥ 5.10 + CONFIG_NET_CLS_CGROUP=y) - 避免在 root 上直接挂
fq_codel:它不响应htb的 borrow/ceil 机制,会导致租户超发后无法被有效压制 - 若用
cake作 leaf,务必关闭其nat模式(设nat off),否则与上层 filter 的匹配逻辑冲突
容易被忽略的内核和命名空间兼容问题
很多线上环境跑着旧内核或容器运行时,导致看似配置正确却无效果:
-
fq_codel的quantum默认值(300)在 10G+ 网卡上易引发小包吞吐瓶颈,建议设为1500;而cake的rtt默认 100ms,在容器内网(通常 rtt 1ms,否则 delay-based drop 完全不触发 - 使用 cgroup v2 限速时,
tc filter必须搭配match u32+classid,且 cgroup path 必须挂载到/sys/fs/cgroup/net_cls(非 unified)—— systemd 默认不启用该子系统 - Pod 级限速(如 Kubernetes)必须通过 CNI 插件注入
tc规则,不能只在宿主机 root qdisc 上配置:容器网络栈独立于 host netns,host 上的 qdisc 对 pod 出向流量无效
真正卡住多租户限速的,从来不是算法选型,而是流量如何精准归类到租户维度。没做 tc filter 分流前,任何 fancy qdisc 都只是在对混合流“公平地乱发”。










