VPS 用 tc 做流量整形:HTB 限速、优先级与防 Bufferbloat 实战(2026)
2026-08-15 · DevCraft Studio
晚高峰 VPS 卡到 SSH 都登不进?本文手把手教你用 Linux 自带的 tc 配合 HTB 对出向做限速与优先级(SSH 优先、批量让路),并用 fq_codel/cake 消除缓冲膨胀,附 IFB 入向整形与开机自启脚本。
你花十几美元买了一台年付廉价 VPS,平时跑个小博客、挂个网络通道、顺手再跑点备份脚本,本来挺美。可一到晚上高峰期,只要后台的 rsync 备份或大文件下载一开,SSH 登录就卡成幻灯片,敲个命令半天才回显,挂在上面的服务也跟着抽风。问题往往不在 CPU,也不在线路质量,而在"出向带宽被一种流量吃满,别的流量全在后面排队"。共享带宽的廉价 VPS 尤其明显:邻居和你抢同一个上联,晚高峰一拥塞,延迟直接上天。这种场景下,光升级配置没用,真正的解法是在机器自己身上做流量整形——用 Linux 内核自带的 tc 配合 HTB 队列,把出向带宽按优先级分配,让 SSH 这种交互流量永远优先,批量任务自觉让路。本文就手把手带你把这套机制在 VPS 上跑起来。
延伸阅读
更多相关攻略推荐:2026 年 VPS 厂商跑路与被收购复盘:如何一眼识别高危 IDC、【去广告 02】VPS 托管 Pi-hole / AdGuard H、【双11黑五 02】2026 黑五 VPS 前瞻总攻略:五大厂商规律、【VPS 进阶玩法精选 029】BuyVM (FranTech) 评、【双11黑五 01】双 11 买 VPS 避坑 + 蹲券全攻略(20。
tc 是什么:Linux 流量控制的统一入口
tc 是 iproute2 工具集里的 Traffic Control 命令,几乎所有现代 Linux 发行版(包括你 VPS 上的 Debian、Ubuntu、AlmaLinux)都自带,不需要额外装什么"QoS 软件"。它操作的是内核里的排队规则(qdisc,queuing discipline)。你可以把网卡出口想象成一个只有一个收费员的收费站:车(数据包)到了只能排队慢慢过。tc 的作用就是决定"谁先过、过多少、超速的怎么办"。
理解 tc 只要记住三层结构:最外层是 qdisc(算法本身,比如 HTB、fq_codel、cake);qdisc 下面可以挂 class(分类,每个类有自己的速率和优先级);class 之间用 filter(过滤器)来分流,过滤器按源/目的 IP、端口、协议甚至 iptables 打的标记来判定一个包该进哪个 class。一句话:qdisc 定规则,class 分快慢车道,filter 当交警。很多人一上来被命令吓退,其实抓住"qdisc 管算法、class 管分层、filter 管分流"这三句话就通了。
为什么廉价共享带宽 VPS 更需要整形
高端独立服务器或独享带宽的机器,上联充裕,偶尔突发也不会堵死;但年付十几刀的廉价 VPS 大多跑在共享上联上,标称 1Gbps 的端口实际是几十上百个邻居共用,机房还会做总带宽限制。两个后果:第一,你自己的批量任务(备份、同步、下载镜像)一旦打满出向,交互流量(SSH、网站响应)就被挤到队尾,表现就是"卡";第二,哪怕你没占满,"缓冲区膨胀(Bufferbloat)"也会害你——路由器/交换机为了不丢包,把发不出去的包堆在超大缓冲里,排队延迟能从几毫秒飙到几百毫秒。
缓冲膨胀是 2010 年前后由 Jim Gettys 等研究者命名的现象,今天在廉价网络设备里依然普遍。它的反直觉之处在于:你以为带宽越大越好,其实真正影响体验的是"在满载时延迟涨多少"。做流量整形,既是限速,也是在主动制造一个"可控的瓶颈",把排队发生在你自己机器上、用聪明的算法消化掉,而不是发生在上游那个你控制不了的傻大缓冲里。对 RackNerd、CloudCone 这类共享带宽机型来说,这一步往往比加钱升级配置更立竿见影。
HTB 限速的核心思路:根类、子类、rate 与 ceil
HTB(Hierarchy Token Bucket,分层令牌桶)是最常用的整形 qdisc。它允许你把一个总带宽切成几块,每块保证一个最低速率(rate),空闲时又能借用别人的额度冲到上限(ceil)。关键参数就两个:rate 是"保底",ceil 是"封顶"。
设计套路是:先建一个根类 1:1,把总带宽(要略低于你实际能跑到的上限,留 5%-10% 余量)设给它;再在它下面开几个子类,比如 1:10 给交互流量保 10M、可冲到满速,1:30 给批量流量保底很低、封顶也压着。default 指没匹配到的流量去哪个类。这样平时各用各的,批量类占满时交互类照样有保底带宽可用。
| 队列 / 算法 | 作用 | 适合场景 |
|---|---|---|
| HTB | 分层限速、按类分配带宽与优先级 | 需要给不同服务分快慢车道 |
| TBF | 简单单流限速(令牌桶) | 只想粗暴限个总速、不在乎分类 |
| fq_codel | 公平排队 + 主动队列管理(AQM) | 挂在 HTB 叶子类里防缓冲膨胀 |
| cake | 限速 + 公平 + 链路开销补偿一体 | 不想细分、一行搞定整端口整形 |
绝大多数"要优先级"的需求,HTB 是起点;但 HTB 只负责"分配",它自己不解决缓冲膨胀,所以每个子类下面还得挂一个会主动丢包的叶子队列(fq_codel 或 cake)。
实战一:用 HTB 给出向做总限速
下面以网卡 eth0、实际上行约 100Mbps 为例,把总限速设到 90Mbps 留余量。所有命令需要 root(sudo)。强烈建议先在服务商控制台(VNC/串行控制台)能登录的情况下操作,万一配错还能救,别只靠 SSH 会话改规则把自已锁外面。
tc qdisc del dev eth0 root 2>/dev/null
tc qdisc add dev eth0 root handle 1: htb default 30
tc class add dev eth0 parent 1: classid 1:1 htb rate 90mbit ceil 90mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 10mbit ceil 90mbit prio 0
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 5mbit ceil 50mbit prio 7
tc qdisc add dev eth0 parent 1:10 fq_codel
tc qdisc add dev eth0 parent 1:30 fq_codel逐行解释:第一行先清掉可能存在的旧规则,避免冲突;第二行挂 HTB 根 qdisc,default 30 表示没匹配到的流量进 1:30;第三行建根类,rate 和 ceil 都设 90mbit,即整机出向封顶 90M;第四、五行建两个子类,1:10 是交互类(prio 0 最高优先级),1:30 是批量类(prio 7 最低);最后两行给每个子类挂上 fq_codel 叶子队列。注意子类 rate 之和可以小于总带宽,空闲时靠 ceil 借用,这才是 HTB 灵活的地方。
实战二:给 SSH 最高优先级,批量任务自觉让路
光限速还不够,关键是分流。最简单的办法是按端口用 u32 过滤器:把源端口 22(SSH 出站响应)和 443(HTTPS 响应)送进 1:10 高优先级类,把 rsync(873)、大文件传输等送进 1:30。
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 22 0xffff flowid 1:10
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 443 0xffff flowid 1:10
tc filter add dev eth0 protocol ip parent 1: prio 5 u32 match ip sport 873 0xffff flowid 1:30这里有个实战坑:如果你用 SSH 通道跑 rsync 备份(端口也是 22),纯端口匹配分不清"交互 SSH"和"SSH 里的备份"。进阶做法是先用 iptables 在 mangle 表给包打标记(MARK),再让 tc 按标记分流,从而把交互和批量在应用层就分开。示例:
iptables -t mangle -A OUTPUT -p tcp --sport 22 -j MARK --set-mark 10
tc filter add dev eth0 parent 1: protocol ip prio 1 handle 10 fw flowid 1:10当然,更省事的是把备份改到非 22 端口(比如 rsync daemon 的 873),端口匹配就能干净区分,不用上 iptables 标记。原则是:能靠端口分清楚的,就别引入 iptables,越少依赖越好排错。
叶子队列用 fq_codel / cake 防 Bufferbloat
HTB 管"分配",但每个类内部怎么排队,还得靠叶子 qdisc。老做法是 SFQ(随机公平排队),只能保证公平、防不了缓冲膨胀;现代做法是 fq_codel(Fair Queuing Controlled Delay)或 cake。它们属于"主动队列管理(AQM)":缓冲区快满时就提前丢包,给 TCP 发减速信号,把排队延迟压在几十毫秒内,而不是等队列塞满才丢。
在 HTB 每个子类下挂 fq_codel 即可(见前面命令里的 tc qdisc add dev eth0 parent 1:10 fq_codel)。如果你嫌 HTB 加分类太麻烦,最直接的一招是用 cake 单独做整端口整形:
tc qdisc del dev eth0 root
tc qdisc add dev eth0 root cake bandwidth 90mbit besteffortcake 等于"HTB + fq_codel + 链路开销补偿 + 按主机/按流公平"打包在一起,一行顶一堆。对纯想消除缓冲膨胀、不在意精细分类的人,cake 是最省心的选择。要测效果,去 bufferbloat.net 或 waveform.com 的 Bufferbloat Test 跑一下,配之前多半是 C/D,配完常能到 A/B——分数看的不是带宽,而是"满载时延迟涨了多少"。
入向整形:tc 默认只能整出向,下载要用 IFB 镜像
一个重要认知:tc 的 root qdisc 只作用于出向(你 VPS 发出去的包)。入向(别人发给你、你的下载)的速率你控制不了——包都已经到了网卡。但你可以"在包被上层协议处理之前先拦下来限速",办法是用 IFB(Intermediate Functional Block)虚拟网卡:把 eth0 的入向流量重定向到 ifb0,再在 ifb0 上挂 HTB/cake。
modprobe ifb
ip link set ifb0 up
tc qdisc add dev eth0 ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
tc qdisc add dev ifb0 root cake bandwidth 90mbit besteffort这套重定向会让 TCP 的拥塞控制以为"对端收不快",从而从源头给发送方减速,等效于把入向也压住,缓冲膨胀同样被消掉。对 VPS 来说,入向整形在你要限制"被别人打满下载"或做下载型代理时特别有用。注意 IFB 设备名可能是 ifb0、ifb1,多个接口做入向时要对应好。
一键脚本 + 开机自启
tc 规则存在内存里,重启网络或机器就清零。生产环境要把它写成脚本并挂开机启动。Systemd 系统可以写一个 oneshot 服务,或在 /etc/network/if-up.d/ 下放脚本(Debian 系 ifupdown),Netplan/networkd 用户用 networkd-dispatcher。要点:脚本开头先 tc qdisc del dev eth0 root 2>/dev/null 清旧规再 apply,避免重复添加报错;如果有 IFB,记得也 up ifb0 并重建 ingress 规则。一个最小脚本骨架:
#!/bin/bash
# /usr/local/sbin/tc-shape.sh
tc qdisc del dev eth0 root 2>/dev/null
tc qdisc add dev eth0 root handle 1: htb default 30
tc class add dev eth0 parent 1: classid 1:1 htb rate 90mbit ceil 90mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 10mbit ceil 90mbit prio 0
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 5mbit ceil 50mbit prio 7
tc qdisc add dev eth0 parent 1:10 fq_codel
tc qdisc add dev eth0 parent 1:30 fq_codel
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 22 0xffff flowid 1:10
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 443 0xffff flowid 1:10嫌手写麻烦,也可以直接装 sqm-scripts(开源项目,由 Toke Høiland-Jørgensen 和 Dave Täht 主导,也是 OpenWrt 的默认 QoS 引擎),它把 cake/fq_codel 的最佳实践封装成配置:填好接口和上下行带宽(同样填实测的 85%-90%),其余全自动。在服务器上 SQM 需要直接访问宿主的 tc 子系统,容器里跑要特权模式,普通 VPS 直接装到系统里最稳。
常见错误与排查
几条老站长踩过的坑:第一,rate 设得比实际上行还高,等于没整,留 5%-10% 余量是铁律;第二,只在出向整却怪下载卡,记住下载要 IFB;第三,配完 SSH 失联,因为把 22 错分到了被限速的类——所以高优先级类务必给 SSH 保底;第四,忘记持久化,重启后规则没了还以为生效。排查三板斧:tc -s qdisc show dev eth0 看各队列收发的包/字节数,tc -s class show dev eth0 看每个类有没有流量进来(某类长期 0 字节说明 filter 没匹配上),tc filter show dev eth0 看过滤器统计。配合 tcpdump 抓一下确认流量真实走的端口,比瞎猜强。
选型建议:RackNerd / CloudCone / BuyVM 怎么玩
三家都是廉价 VPS 代表,整形思路一致,差别在带宽画像:
| 厂商 | 带宽特征 | 整形建议 |
|---|---|---|
| RackNerd | 多接 ColoCrossing 洛杉矶,晚高峰共享上联拥挤 | 上 HTB 保 SSH,出向限到实测 9 成 |
| CloudCone | 洛杉矶机房,支持支付宝/加密货币 | 拿来练手,cake 一行最省心 |
| BuyVM | 带宽厚道、自带 DDoS 过滤,部分机房量足 | cake 吃满余量又不被缓冲膨胀坑 |
RackNerd 晚高峰邻居抢带宽最明显,最该上 HTB 把 SSH 顶到最高优先级;CloudCone 同样洛杉矶、国内付款方便,适合新手拿来做实验;BuyVM 以带宽厚道和自带过滤著称,部分机房给的量足,cake 一行就能把余量吃满又不被 bufferbloat 坑。无论哪家,先把出向总速限制在实测的 9 成,再按本文分层,晚高峰体验立竿见影。延伸阅读:更多 VPS 网络与带宽主题,见 VPS 主题导读中心。
#VPS流量整形 #tc限速 #HTB #Bufferbloat #QoS