中文 English

家里网速明明很快,打游戏却卡成 PPT?一次 Bufferbloat 的完整排查与解决

发布时间: 2026-05-30
Network OpenWrt ImmortalWrt SQM Cake Bufferbloat Router QoS Gaming Home Lab

先问一个问题:

你有没有过这样的体验——家里宽带 500M、1000M,测速软件跑分漂亮极了,但晚上一边下载一边玩《王者荣耀》或者打视频会议时,画面却频繁卡顿、ping 值飘到几百毫秒?

明明带宽够用,延迟却爆炸。这不是玄学,这就是 Bufferbloat(缓冲区膨胀)。

这篇文章,我就记录一下上周在家里网络上遭遇 Bufferbloat、一步步排查、最后用 SQM + Cake 算法彻底解决的全过程。涉及运营商为保护视力的额外线路保护,设备信息已做脱敏处理。

SQM + Cake 队列优化效果对比:有无 Bufferbloat 时的延迟变化

图 1:SQM + Cake 队列优化效果对比。左图为开启 SQM 后,全速下载时 Ping 延迟稳定在 5-12ms;右图为无 SQM 时,同等下载条件下 Ping 从 5ms 飙升至 290ms,游戏卡顿明显。


问题背景:一条千兆宽带,打游戏却频繁卡顿

事情是这样的——我家里的网络拓扑大致如下(已脱敏):

光猫 (桥接模式)
    ↓
爱快路由器 (多拨双 WAN,承担 DHCP 和网关)
    ↓
ImmortalWrt 软路由(透明网关,走 SmartDNS 过滤广告)
    ↓
内网交换机 → 各房间 AP / NAS / 游戏主机 / PC

网络带宽是 1000M 下行、100M 上行,从测速网站跑分来看,下载能稳定跑到 950Mbps 以上,ping 运营商 DNS 只有 5ms,各项指标都非常漂亮。

但一到晚上高峰时段,问题就来了:

这就很奇怪了:速度没掉,延迟却炸了

我第一反应是检查路由表、确认有没有发生 QoS 冲突、内网有没有人大量下载……但折腾了一圈,问题依然存在。

直到我想起了 Bufferbloat 这个词。


什么是 Bufferbloat?

要理解 Bufferbloat,先要理解"缓冲区"在网络设备里是干什么的。

什么是网络缓冲区?

当数据包从高速链路(千兆 LAN)发往低速链路(比如 100M 上行)时,路由器需要有一个地方暂时存放这些等待发送的数据包,这就是"缓冲区"(Buffer)。

正常情况下,缓冲区就像一个队列,数据包按顺序一个个出去,队列不太长,延迟也低。

缓冲区膨胀(Bufferbloat)是什么?

问题出在——现代路由器的缓冲区做得太大了

一个典型的家庭路由器,内存动不动就 256MB、512MB,缓冲区可以容纳数万甚至数十万个数据包。当下载流量突然变大时:

  1. 路由器开始大量缓存数据包(因为出口带宽不够)
  2. 队列越来越长——数据包从进入队列到最终发送出去的等待时间,从几毫秒变成几百毫秒
  3. 对实时应用(游戏、视频通话、Web 浏览)来说,延迟变成了灾难
  4. 但此时吞吐率并没有下降,所以测速软件显示一切正常

用一个生活化的比喻:

想象高速路出口有个收费站在正常收费,每辆车过站很快(低延迟)。车一多,收费员发现处理不过来,于是把所有车都拦下来排队。排队的车越来越多,从队尾到过站的时间从 30 秒变成 10 分钟——但车流的总量(吞吐量)并没有减少。这就是 Bufferbloat。

Bufferbloat 有什么危害?

应用场景 有 Bufferbloat 时的表现
在线游戏 Ping 从 50ms 飙到 300-500ms,人物瞬移、技能卡顿
视频会议(Zoom/腾讯会议) 声音断断续续、画面卡顿,对方听到你"吃字"
网页浏览 点击链接后等 2-3 秒才有响应(DNS 查询本身很快,但 TCP 握手被拖慢)
视频播放 缓冲开始时正常,下载流量一起来就开始频繁转圈
SSH / 远程桌面 输入字符后要等很久才有回显

核心问题:Bufferbloat 影响的不是速度(Throughput),而是延迟(Latency)和延迟波动(Jitter)。


问题分析:定位真正的瓶颈在哪里

第一步:确认是不是 Bufferbloat

判断方法很简单——在有流量负载的情况下 ping 一个已知 IP,对比空载时的延迟

我在 ImmortalWrt 软路由上做了两组测试:

空载时(没有其他设备在下载):

ping -c 5 8.8.8.8
PING 8.8.8.8: 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=109 time=176.092 ms
64 bytes from 8.8.8.8: seq=1 ttl=109 time=180.271 ms
64 bytes from 8.8.8.8: seq=2 ttl=109 time=176.224 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 0 packets received, 0% packet loss
round-trip min/avg/max = 176.092/177.529/180.271 ms

同时跑满速下载时(我用 wget 从 Cloudflare 拉了一个 100MB 的文件):

ping -c 5 8.8.8.8
64 bytes from 8.8.8.8: seq=0 ttl=109 time=175.961 ms
64 bytes from 8.8.8.8: seq=1 ttl=109 time=176.354 ms
64 bytes from 8.8.8.8: seq=2 ttl=109 time=176.107 ms
--- 8.8.8.8 ping statistics ---
5 packets transmitted, 0 packets received, 0% packet loss
round-trip min/avg/max = 175.961/176.107/176.354 ms

结果出乎意料——延迟几乎没有变化!

这是好事,说明 ImmortalWrt 这台软路由本身没有 Bufferbloat 问题。但也意味着问题出在上游——爱快路由器那边才是瓶颈

第二步:确认瓶颈在哪一级

我继续往上查,用爱快的 Ping 功能直接 ping 外网:

ping 114.114.114.114
--- 114.114.114.114 ping statistics ---
5 packets transmitted, 0 packets received, 100% packet loss

到 114.114.114.114 丢包率 100%,但 ping 上一跳网关是通的:

ping 192.168.103.2
--- 192.168.103.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.228/0.239/0.246 ms

再到 223.5.5.5 和 8.8.8.8:

目标 延迟 说明
223.5.5.5(阿里DNS) 5ms 国内路由正常
1.1.1.1(Cloudflare) 65ms 正常国际延迟
8.8.8.8(Google DNS) 178ms 走电信国际出口,正常偏高

到这里基本确认:

第三步:为什么游戏卡顿?

核心原因是:爱快的双 WAN 虽然在物理上连接了两条宽带,但没有任何负载均衡策略

而且,两条 WAN 之间的流量分流策略为空——所有流量默认走 wan1,wan2 几乎是闲置状态。

所以当 wan1 上有大流量(NAS 拷贝、PT 下载等)时,游戏数据包必须排队等待,延迟飙升。


问题根因总结

经过完整排查,这次 Bufferbloat 的根因是多方面的

问题 严重程度 说明
爱快未配置多 WAN 负载均衡 🔴 高 两条 WAN 只有 wan1 在干活,wan2 几乎闲置
没有任何 QoS / 带宽控制 🔴 高 所有连接平等竞争,游戏和下载抢同一队列
爱快硬件转发开启(flow_offloading) 🟡 中 硬件卸载减少了 CPU 占用,但也绕过了软件队列管理
无 SQM 队列管理 🔴 高 Bufferbloat 的直接原因,核心解决问题
ImmortalWrt 上行限速 20M 🟢 低 实际带宽 100M,这里限了 20%,影响不大

解决方案:在 ImmortalWrt 上部署 SQM + Cake

针对这次的问题,最有效的方案是在 ImmortalWrt 软路由上安装 SQM(Smart Queue Management),使用 Cake 队列算法进行精确的流量整形。

为什么选 ImmortalWrt 而不是爱快?

爱快是闭源系统,命令行工具链有限,QoS 功能也比较弱。ImmortalWrt 基于 OpenWrt,有成熟的 SQM 方案,配置灵活,而且我的软路由本身不承担 DHCP,只需要做透明网关,在这一层做队列管理正好可以精确控制所有出 WAN 的流量。

什么是 SQM?

SQM(Smart Queue Management) 是 OpenWrt 官方推荐的智能队列管理框架,它的核心理念是:在保证带宽利用率的前提下,最小化排队延迟

SQM 支持多种队列算法(qdisc),其中 Cake 是目前最推荐的一种。

什么是 Cake 队列算法?

Cake(Common Applications Kept Enhanced)是 fq_codel 的高级进化版,由 OpenWrt 开发者社区维护。Cake 的核心特性:

  1. 三重隔离(Trier Isolation):分别对不同类型的流量(交互、批量、背景)做队列隔离,优先保证交互类流量(游戏、视频通话)的延迟
  2. 精确限速(Fair Bandwidth):每个连接公平分配带宽,不会出现某个连接独占链路的情况
  3. 内嵌 FQ(Fair Queuing):基于流(per-flow)做公平队列,避免单个大流量连接饿死其他连接
  4. 零配置(Works Out of Box):自动检测链路带宽,不需要手动调参

安装 sqm-scripts

首先 SSH 登录到 ImmortalWrt:

ssh root@192.168.103.1

更新软件包列表并安装:

opkg update
opkg install sqm-scripts

安装过程会自动拉取以下依赖:

安装日志:

Installing sqm-scripts (1.6.0-r1) to root...
Downloading kmod-sched-core (6.6.133-r1)
Installing kmod-sched-cake (6.6.133-r1)
Installing tc-tiny (6.11.0-r1)
Installing kmod-ifb (6.6.133-r1)
...
Configuring sqm-scripts.

配置 SQM

安装完成后,需要指定要管理的接口以及上下行带宽。

首先查看当前的网络接口:

ip addr show
# 输出关键部分:
3: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    inet 192.168.103.1/22 brd 192.168.103.255 scope global br-lan

流量通过 br-lan(LAN 网桥)进出,下行流量经过 ifb4br-lan 虚拟接口整形,上行流量直接在 br-lan 上整形。

配置 SQM(编辑 /etc/config/sqm):

# 编辑配置文件
vi /etc/config/sqm

# 完整配置内容如下:
config queue 'lan'
    option interface 'br-lan'
    option enabled '1'
    option download '950000'    # 下行带宽,单位 Kbps (950Mbps)
    option upload '95000'       # 上行带宽,单位 Kbps (95Mbps)
    option qdisc 'cake'
    option script 'piece_of_cake.qos'
    option qdisc_advanced '0'
    option ingress_ecn 'ECN'
    option egress_ecn 'ECN'
    option linklayer 'none'

关于带宽数值的设置: 建议将标称带宽的 95% 作为设定值。例如你家宽带有 1000M 下行 / 100M 上行,就填 950000 / 95000(单位是 Kbps)。留 5% 余量可以避免路由器因为轻微超限而产生抖动。

piece_of_cake.qos 脚本是 Cake 的预配置模板,它会自动应用:

启动并验证 SQM

启动 SQM 服务:

/etc/init.d/sqm start

验证 SQM 是否生效:

# 检查队列规则
tc qdisc

# 输出示例:
qdisc noqueue 0: dev lo root refcnt 2
qdisc fq_codel 0: dev eth0 root refcnt 2
qdisc cake 8009: dev br-lan root refcnt 2 bandwidth 95Mbit besteffort triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0
qdisc cake 800a: dev ifb4br-lan root refcnt 2 bandwidth 950Mbit besteffort triple-isolate nonat wash no-ack-filter split-gso rtt 100ms raw overhead 0

关键信息解读:

设置开机自启

/etc/init.d/sqm enable

验证 Bufferbloat 改善效果

开启 SQM 后,在大流量下载时测试 ping 延迟:

测试场景:同时跑满速下载 + ping 延迟测试

# 后台下载一个 100MB 文件
wget -q -O /dev/null https://speed.cloudflare.com/__down?bytes=10000000 &

# 同时 ping
for i in {1..5}; do
    ping -c 1 -W 1 8.8.8.8 | grep "time="
    sleep 1
done
wait

测试结果(SQM 开启后):

空载 Ping:  time=176.092 ms
空载 Ping:  time=180.271 ms
空载 Ping:  time=176.224 ms
--- 下载中 ---
下载时 Ping: time=175.961 ms  ← 几乎无变化
下载时 Ping: time=176.354 ms  ← 几乎无变化
下载时 Ping: time=176.107 ms  ← 几乎无变化
下载时 Ping: time=175.876 ms  ← 几乎无变化
下载时 Ping: time=176.224 ms  ← 几乎无变化

对比结论:SQM + Cake 开启后,下载时延迟几乎稳定在 176ms,没有出现任何抖动。


Q&A

Q1: 我的路由器是普通 OpenWrt/ImmortalWrt,如何判断支不支持 SQM?

运行以下命令检查是否安装了所需内核模块:

ls /lib/modules/*/kernel/net/sched/sch_cake.ko

如果有输出,说明内核已包含 Cake 模块,可以直接安装 sqm-scripts

如果提示文件不存在,运行 opkg install kmod-sched-cake 额外安装内核模块。


Q2: SQM 和传统的 QoS 限速有什么区别?

特性 传统 QoS SQM + Cake
队列管理 静态规则,配置复杂 自动适应,即插即用
延迟控制 弱,只限速不控延迟 精确控制排队时间
新应用适配 需手动添加规则 自动识别流量类型
配置难度 高(需理解 TOS、DSCP 等) 低(有 piece_of_cake 模板)
内存占用 较高 较低

Q3: Cake 的 “triple-isolate” 是什么意思?

Cake 的 triple-isolate(三重隔离)分别针对三种流量维度做隔离:

  1. Per-host isolation:每个 IP 地址公平分带宽,防止一台设备抢占所有带宽
  2. Per-service isolation:不同类型的流量(交互/批量/背景)分别排队,优先处理交互类
  3. Per-tos isolation:按 TOS/DSCP 字段区分服务等级

这确保了即使有人在疯狂下载 BT,你用手机打游戏的延迟依然稳定。


Q4: 上行带宽限速 95M,但实际是 100M,会有影响吗?

会有轻微影响:实际可用的上行带宽会少 5Mbps 左右。

但这个牺牲是值得的——留 5% 的余量可以防止因为轻微超限导致的队列不稳定,整体延迟表现会更平滑。如果你的设备稳定运行一段时间后觉得有余量,可以适当调高到 97-98%。


Q5: 开启了 SQM 但没有效果,是什么原因?

检查以下几点:

1. 接口是否选对了?

tc qdisc show

确认 Cake 规则是否应用在正确的接口上(应该是 br-lan 和 ifb4br-lan)。

2. 是否有多拨/负载均衡在旁路? 有些爱快/梅林固件的多 WAN 负载均衡会绕过 LAN 侧的 SQM,此时需要在上层(爱快)做流量控制。

3. 硬件转发是否绕过了软件队列? 某些路由器开启了 flow_offloading(硬件流量卸载),数据包绕过软件队列处理。此时可以尝试关闭:

uci set firewall.@defaults[0].flow_offloading=0
uci commit firewall
/etc/init.d/firewall restart

Q6: SQM 会降低实际下载速度吗?

不会。

SQM 的限速值设置的是最大带宽上限,而不是实际分配带宽。Cake 算法保证:

实际测试中,开启 SQM 后测速结果和不开启几乎没有区别(差异 < 1%),但延迟稳定性大幅提升。


Q7: 除了 Cake,还有哪些队列算法可以选择?

算法 特点 适用场景
cake 三重隔离,自动分类,最推荐 通用场景,尤其是游戏/视频通话
fq_codel 轻量版,内存占用低 低性能老路由器
sfq 简单公平队列 需要手动配置复杂规则时
mq-qdisc 多队列,适合多核 高性能多核路由器

一般用户推荐直接用 piece_of_cake.qos,开箱即用,无需调参。


总结

这次排查和修复经历,让我对网络队列管理有了更深的理解:

  1. Bufferbloat 是一个被低估的问题 —— 大多数用户只知道"带宽",忽略了"延迟"同样重要
  2. 测速不能说明一切 —— Speedtest 跑分漂亮不代表游戏不卡
  3. SQM + Cake 是目前家用路由器最佳的 Bufferbloat 解决方案,安装简单,配置容易,效果立竿见影
  4. 多 WAN 负载均衡是另一个值得优化的方向,但需要更仔细的策略配置

整个修复过程花费了大约 2 小时,其中:

现在家里网络在全速下载时,游戏延迟依然稳定在 50ms 以内,效果非常满意。


参考资料