tc 命令详解
更新时间:2026-09-17。本文是「一个命令一个文档」系列,聚焦
tc(traffic control,流量控制)——属于网络进阶与压测命令族。它在内核的发送/接收队列上做文章:限速、排队、加延迟、丢包,是不依赖真实网络环境就能"制造弱网"和做 QoS 的利器。
tc 管理的对象是 qdisc(queueing discipline,排队规则,发音 "queue discipline")。出站数据包先进入挂在网卡上的 qdisc 排队,再由驱动发出;tc 通过给 qdisc 挂 class(分类)和 filter(分类器)实现差异化调度。最广为人知的两类用途是 netem 弱网模拟与 htb/tbf 带宽限制。
一、三件套心智模型
| 对象 | 角色 | 类比 |
|---|---|---|
| qdisc | 队列调度规则,挂在网卡根上 | 交通总调度 |
| class | qdisc 下的分类,每类一套速率/优先级 | 公交专用道、普通车道 |
| filter | 把包匹配到某个 class 的规则 | 按车牌分流 |
tc qdisc show dev eth0 # 看当前根队列(默认多为 pfifo_fast / fq_codel / mq)
tc qdisc add dev eth0 root ... # 挂根 qdisc(root 只能有一个)
tc qdisc del dev eth0 root # 删除、恢复默认(测完务必清理)一台机器的一张网卡 root qdisc 只有一个;重复
add root会报 "File exists",要先del或用replace。弱网模拟完一定tc qdisc del dev eth0 root清规则——忘了删会让整台机持续高延迟,是非常常见的事故。
二、netem:模拟弱网(最常用)
tc qdisc add dev eth0 root netem delay 100ms # 固定 +100ms 延迟
tc qdisc add dev eth0 root netem delay 100ms 20ms # 延迟 100ms ± 20ms 抖动
tc qdisc add dev eth0 root netem loss 5% # 5% 丢包
tc qdisc add dev eth0 root netem loss 5% 25% # 5% 基础丢包 + 25% 相关性(突发丢包)
tc qdisc add dev eth0 root netem delay 100ms reorder 25%# 25% 包乱序
tc qdisc add dev eth0 root netem duplicate 1% # 1% 重复包
tc qdisc add dev eth0 root netem delay 80ms loss 2% # 延迟和丢包可叠加
tc qdisc change dev eth0 root netem delay 200ms loss 10% # 不删直接改参数上线前用 netem 能廉价验证很多平时测不到的行为:超时设置是否合理、重试会不会雪崩、乱序下 TCP/应用协议是否健壮、移动网络 200ms+ RTT 时交互是否可用。注意 netem 默认主要作用在**出站(egress)**方向,要给入站限速通常借助
ifb(虚拟网卡)把入向流量引到出向再控。
三、htb / tbf:带宽限制
# tbf:简单整卡限速(令牌桶),限到 100mbit、允许突发
tc qdisc add dev eth0 root tbf rate 100mbit burst 32kbit latency 400ms
# htb:分类限速,给不同流量分带宽
tc qdisc add dev eth0 root handle 1: htb default 20
tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 60mbit ceil 100mbit # 保证60、可借到100
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 20mbit ceil 40mbit
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 443 0xffff flowid 1:10HTB 的
rate是保证带宽、ceil是空闲时能借到的上限,适合"关键业务保底、非关键可超卖"的 QoS。整卡简单限速用 tbf 更省事;要按端口/IP 差异化才需要 htb+class+filter 这套。
四、缓冲膨胀与现代 qdisc
传统 pfifo_fast 队列可以排得很深,拥塞时缓冲区积压导致延迟飙升,即 bufferbloat(缓冲膨胀)。现代发行版默认转向:
| qdisc | 特点 |
|---|---|
fq_codel | 公平队列 + CoDel 主动队列管理,用延迟而非丢包信号抑制膨胀,默认主流 |
cake | fq_codel 增强版,集成 ACK 过滤、按流整形、Diffserv |
fq | 按流排队,配合 TCP pacing/BBR 常用 |
高带宽下延迟反而抖动,先
tc qdisc show看是不是深队列的老 qdisc,换fq_codel/cake常能显著降低满载时的 RTT。这与TCP 拥塞控制和排队/缓冲调优是同一主题的内核侧。
五、常见坑
RTNETLINK answers: File exists # root qdisc 已存在:先 del 或用 replace/replace
# 容器里:tc 控的是网卡,docker 容器要在容器 netns 内执行,或对 veth/ifb 操作
tc -s qdisc show dev eth0 # -s 带统计:看丢包/入队/限流计数,判断规则是否真生效规则加了但"没效果",用
tc -s qdisc show看该 qdisc 的 packets/bytes/drop 计数是否在涨;并确认你测的流量走的是这张网卡、这个方向(egress)。改完用 iperf3 打流验证速率、用 ping 看延迟是否符合设定。
相关命令
链路质量用 ping/mtr,带宽压测用 iperf3(见网络进阶与压测),网卡硬件队列与 ring 用 ethtool,抓包用 tcpdump。原理见TCP 拥塞控制与内核网络调优。
总结
tc = 内核流量控制,围绕 qdisc/class/filter 三件套:弱网模拟用 tc qdisc add dev eth0 root netem delay/loss/reorder(测完务必 del root),整卡限速用 tbf、差异化 QoS 用 htb 的 rate/ceil + u32 filter;高带宽延迟抖动想到缓冲膨胀,换 fq_codel/cake;规则是否生效用 tc -s qdisc show 的计数确认。