tc限速不准主因是qdisc类型选错(如误用pfifo_fast)或根设备绑定错误(须用egress root而非parent,禁用ingress);容器需clsact+cgroup2实现进程级限速,iptables限速须在POSTROUTING打标配合egress策略。

tc 命令限速不准?关键在 qdisc 类型和根设备选择
Linux 下用 tc 限速失效或波动大,多数情况不是命令写错,而是选错了队列规则(qdisc)类型或绑错了网络接口。默认的 pfifo_fast 不支持速率控制,必须显式指定如 htb 或 tbf;且限速必须施加在**出口方向(egress)**,不能对 loopback 或虚拟网卡(如 docker0)直接生效。
-
tc qdisc add dev eth0 root htb default 30—— 必须用root(非parent),否则无法接管全部出向流量 - 容器或 Docker 场景下,宿主机上对
eth0限速只影响从宿主机发出的包,容器内进程的出向流量需在docker0或使用clsact+tc filter匹配 cgroup -
tbf简单但无分类能力,突发(burst)设太小会导致 TCP ACK 丢包、吞吐骤降;htb更稳,但需配合tc class和tc filter才能按 IP/端口分流
保障某服务带宽不被挤占:用 htb + cgroup2 实现进程级隔离
单纯给 IP 或端口限速无法解决“同一台机器上多个服务争抢带宽”的问题。真正可控的方式是把进程归入 cgroup2,并用 tc 的 clsact qdisc 结合 matchall 过滤器绑定到 cgroup。
- 确认内核启用 cgroup2:检查
/proc/cgroups中memory行的第 4 列是否为 1;Ubuntu 22.04+ 默认启用 - 创建 cgroup 并设置 net_cls:
mkdir /sys/fs/cgroup/myapp echo 0x00110011 > /sys/fs/cgroup/myapp/net_cls.classid
其中0x00110011是主类 ID(前 16 位)+ 子类 ID(后 16 位),后续 tc class 需匹配前 16 位 - 启动进程时加入 cgroup:
sudo cgexec -g net_cls:/myapp curl http://example.com - 在网卡上挂 clsact:
tc qdisc add dev eth0 clsact,再用tc filter add dev eth0 parent ffff: protocol ip flower skip_sw indev eth0 classid 0x00110011
iptables + tc 联动做源 IP 限速:为什么 mangle 表 PREROUTING 不起作用
想对进来的连接限速(比如限制某客户端上传速度),不能在 PREROUTING 链打标记,因为 tc 的 egress 限速只管发出去的包,而 PREROUTING 处理的是刚进来的包——此时还没走到 egress 队列。正确路径是:对**应答包(即服务器回包)** 打标,再在 egress 上按标记限速。
- 给特定源 IP 的响应流量打标记:
iptables -t mangle -A POSTROUTING -s 192.168.1.100 -j CLASSIFY --set-class 1:10 - 对应 tc class 必须建在 root htb 下:
tc class add dev eth0 parent 1: classid 1:10 htb rate 2mbit - 注意:若服务器启用了 conntrack,且连接是 NAT 过来的(如 SNAT),
-s应该匹配 NAT 后的源地址(通常是内网地址),而非原始客户端 IP
实时监控限速效果:别只看 ifconfig,要用 tc -s 和 ip -s
ifconfig eth0 显示的 RX/TX 是底层驱动收发计数,不反映 tc 是否真在丢包或延迟。实际策略是否生效,得查 tc 自身统计和 qdisc 排队状态。
- 查看某 class 的实时丢包与排队长度:
tc -s class show dev eth0,重点关注dropped、overlimits、qlen - 查过滤器命中次数:
tc -s filter show dev eth0 parent ffff:(clsact)或tc -s filter show dev eth0 parent 1:(htb) - 验证 cgroup 绑定是否成功:
cat /proc/[pid]/cgroup看进程是否在目标 cgroup;再查cat /sys/fs/cgroup/myapp/net_cls.classid确认值一致 - 误将限速设在 ingress(
tc qdisc add dev eth0 ingress)会导致完全无效——ingress 在 Linux 中仅支持简单重定向,不支持速率整形










