你的 1Gbps 链路上跑着视频流、数据库备份、API 请求和 SSH 会话。没有流量管理时,一个大文件传输就能让 SSH 卡顿,一次数据库备份就能让 API 延迟飙升。带宽管理不是限制——而是保证关键业务在任何负载下都能获得所需的网络资源。
一、Linux tc 架构
1.1 三层模型
Linux Traffic Control(tc)由三个核心概念组成:
┌──────────────┐
│ filter │ 分类器:决定包归入哪个 class
│ (u32/bpf/fw) │
└──────┬───────┘
│ 分类
┌──────┴───────┐
│ class │ 类:定义带宽配额和优先级
│ (HTB/CBQ) │
└──────┬───────┘
│ 排队
┌──────┴───────┐
│ qdisc │ 队列规则:决定包的排队和调度方式
│(pfifo/fq/fq_ │
│ codel/netem)│
└──────────────┘
1.2 qdisc 分类
| 类型 | qdisc | 特点 | 适用场景 |
|---|---|---|---|
| 无类 | pfifo_fast | 简单 FIFO | 默认 qdisc |
| 无类 | fq | 公平队列 | BBR 配合使用 |
| 无类 | fq_codel | 公平队列 + AQM | 通用推荐 |
| 无类 | tbf | 令牌桶 | 简单限速 |
| 无类 | netem | 网络模拟 | 测试环境 |
| 有类 | htb | 分层令牌桶 | 带宽分配 |
| 有类 | cbq | 类基础队列 | 已过时 |
| 有类 | prio | 优先级 | 简单优先级 |
1.3 基本操作
# 查看当前 qdisc
tc qdisc show dev eth0
# 查看统计信息
tc -s qdisc show dev eth0
# 查看 class
tc class show dev eth0
# 查看 filter
tc filter show dev eth0
# 删除所有规则
tc qdisc del dev eth0 root 2>/dev/null二、TBF 令牌桶限速
2.1 TBF 原理
令牌桶过滤器(Token Bucket Filter):
令牌以固定速率 rate 产生,积攒在桶中
每个数据包消耗与其大小等量的令牌
桶满时令牌被丢弃
没有令牌时数据包被延迟或丢弃
┌─────────────────────────┐
│ 令牌桶(burst 大小) │
│ ████████░░░░░░░░ │
│ │
│ 令牌产生速率 = rate │
└────────────┬─────────────┘
│ 令牌
┌────┴────┐
包 ────→│ 匹配 │────→ 发送
└────┬────┘
│ 无令牌
↓
延迟/丢弃
2.2 TBF 配置
# 限制 eth0 出口带宽为 100Mbps
tc qdisc add dev eth0 root tbf \
rate 100mbit \
burst 256kb \
latency 50ms
# 参数说明:
# rate — 令牌产生速率(=限制的带宽)
# burst — 桶大小(允许的突发量)
# latency — 最大延迟(或用 limit 指定队列字节数)
# burst 的计算:
# burst >= rate / HZ(内核定时器频率)
# 对于 100Mbps,HZ=1000:burst >= 100000000/8/1000 = 12500 bytes
# 实际建议设置更大(几十 KB 到几百 KB)
# 验证
tc -s qdisc show dev eth0
# qdisc tbf 8001: root rate 100Mbit burst 256Kb lat 50ms
# Sent 1234567 bytes 8901 pkt (dropped 0, overlimits 0)三、HTB 分层令牌桶
3.1 HTB 分层结构
HTB(Hierarchical Token Bucket)允许创建带宽分配的层级结构:
root qdisc (HTB)
└── class 1:1(总带宽 1Gbps)
├── class 1:10(高优先级 - 500Mbps 保证,可借用到 1Gbps)
│ ├── filter: 目标端口 80/443
│ └── leaf qdisc: fq_codel
├── class 1:20(中优先级 - 300Mbps 保证,可借用到 800Mbps)
│ ├── filter: 目标端口 3306/5432
│ └── leaf qdisc: fq_codel
└── class 1:30(低优先级 - 200Mbps 保证,不可借用)
├── filter: 其他流量
└── leaf qdisc: fq_codel
3.2 HTB 完整配置
#!/bin/bash
# htb-setup.sh — HTB 带宽管理配置
DEV=eth0
TOTAL_BW=1gbit
# 清除旧规则
tc qdisc del dev $DEV root 2>/dev/null
# 创建 root qdisc
tc qdisc add dev $DEV root handle 1: htb default 30
# 根 class — 总带宽上限
tc class add dev $DEV parent 1: classid 1:1 htb \
rate $TOTAL_BW ceil $TOTAL_BW
# 高优先级:Web 流量(保证 500M,最大 1G,优先借用)
tc class add dev $DEV parent 1:1 classid 1:10 htb \
rate 500mbit ceil 1gbit prio 1
# 中优先级:数据库流量(保证 300M,最大 800M)
tc class add dev $DEV parent 1:1 classid 1:20 htb \
rate 300mbit ceil 800mbit prio 2
# 低优先级:其他流量(保证 200M,不额外借用)
tc class add dev $DEV parent 1:1 classid 1:30 htb \
rate 200mbit ceil 200mbit prio 3
# 为每个叶子 class 添加 fq_codel qdisc
tc qdisc add dev $DEV parent 1:10 handle 10: fq_codel
tc qdisc add dev $DEV parent 1:20 handle 20: fq_codel
tc qdisc add dev $DEV parent 1:30 handle 30: fq_codel
# 分类规则
# Web 流量 → class 1:10
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip dport 80 0xffff flowid 1:10
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip dport 443 0xffff flowid 1:10
# 数据库流量 → class 1:20
tc filter add dev $DEV parent 1: protocol ip prio 2 u32 \
match ip dport 3306 0xffff flowid 1:20
tc filter add dev $DEV parent 1: protocol ip prio 2 u32 \
match ip dport 5432 0xffff flowid 1:20
# 其他流量 → class 1:30(default 已设置)
echo "HTB 配置完成"
tc -s class show dev $DEV3.3 HTB 参数详解
| 参数 | 含义 | 说明 |
|---|---|---|
| rate | 保证带宽 | 即使其他 class 空闲也能获得 |
| ceil | 最大带宽 | 其他 class 空闲时可以借用到此值 |
| burst | 令牌桶大小 | rate 对应的桶 |
| cburst | ceil 对应的桶 | ceil 的突发量 |
| prio | 优先级 | 数字越小优先级越高 |
| quantum | 借用粒度 | DRR 轮询的字节数 |
# rate vs ceil 的关系:
# rate = 300M, ceil = 800M 意味着:
# - 该 class 至少能获得 300Mbps
# - 当其他 class 有空闲带宽时,可以使用到 800Mbps
# - 绝不超过 800Mbps
# rate = ceil 意味着不借用,严格限制四、fq_codel 公平队列
4.1 CoDel 算法
CoDel(Controlled Delay)是一种主动队列管理(AQM)算法,专门解决 Bufferbloat:
# fq_codel = Fair Queue + CoDel
# Fair Queue:每个流一个子队列,轮询调度
# CoDel:当排队延迟超过阈值时丢包
# 用 fq_codel 替换默认 qdisc
tc qdisc replace dev eth0 root fq_codel
# 带参数配置
tc qdisc replace dev eth0 root fq_codel \
limit 10240 \
target 5ms \
interval 100ms \
flows 1024 \
quantum 1514
# 参数说明:
# limit — 总队列包数上限
# target — 可接受的最小排队延迟(默认 5ms)
# interval — 调整窗口(默认 100ms)
# flows — 流的哈希桶数
# quantum — DRR 轮询量
# 查看统计
tc -s qdisc show dev eth0
# qdisc fq_codel 8001: root
# maxpacket 1514 drop_overlimit 0 new_flow_count 12345
# ecn_mark 0 new_flows_len 0 old_flows_len 54.2 CAKE——更现代的 AQM
# CAKE(Common Applications Kept Enhanced)
# 比 fq_codel 更全面,集成了限速 + AQM + 公平 + 流量整形
# 简单用法——只需指定带宽
tc qdisc replace dev eth0 root cake bandwidth 900mbit
# 完整配置
tc qdisc replace dev eth0 root cake \
bandwidth 900mbit \
besteffort \
flowblind \
nat \
wash
# 参数说明:
# bandwidth — 链路带宽(设为实际带宽的 90-95%)
# besteffort — 所有流量同等对待
# nat — NAT 环境下正确识别流
# wash — 清除上游 DSCP 标记
# CAKE vs fq_codel
# CAKE:一体化解决方案,配置简单
# fq_codel:需要配合 HTB 等使用,更灵活五、netem 网络模拟
5.1 延迟模拟
# netem 用于模拟真实网络条件——延迟、丢包、抖动、重排序
# 添加固定延迟
tc qdisc add dev eth0 root netem delay 100ms
# 添加延迟 + 抖动(正态分布)
tc qdisc add dev eth0 root netem delay 100ms 20ms
# 延迟在 80-120ms 之间波动
# 添加延迟 + 相关性
tc qdisc add dev eth0 root netem delay 100ms 20ms 75%
# 75% 相关性——前一个包延迟大,后一个也可能大
# 使用不同分布
tc qdisc add dev eth0 root netem delay 100ms 20ms distribution pareto
# 可选:normal, pareto, paretonormal5.2 丢包与重排序
# 随机丢包
tc qdisc add dev eth0 root netem loss 1%
# 突发丢包(Gilbert-Elliott 模型)
tc qdisc add dev eth0 root netem loss gemodel 1% 10% 70% 0.1%
# p13=1% 坏→好的概率
# p31=10% 好→坏的概率
# p32=70% 坏状态继续坏的概率
# p14=0.1% 概率
# 包重排序
tc qdisc add dev eth0 root netem delay 100ms reorder 25% 50%
# 25% 的包不延迟(到达更早),50% 相关性
# 包重复
tc qdisc add dev eth0 root netem duplicate 1%
# 包损坏
tc qdisc add dev eth0 root netem corrupt 0.1%5.3 组合使用
# 模拟跨大洲网络:100ms 延迟 + 20ms 抖动 + 0.5% 丢包 + 带宽限制
tc qdisc del dev eth0 root 2>/dev/null
# 方法:netem + tbf 组合
tc qdisc add dev eth0 root handle 1: netem \
delay 100ms 20ms distribution normal \
loss 0.5%
tc qdisc add dev eth0 parent 1: handle 2: tbf \
rate 50mbit burst 256kb latency 50ms
# 验证
ping -c 10 target
# rtt min/avg/max/mdev = 80/100/120/20 ms
# 删除所有规则
tc qdisc del dev eth0 root5.4 CI/CD 中的网络模拟
#!/bin/bash
# network-test.sh — 在 CI 中模拟不同网络条件测试应用
test_under_network_condition() {
local desc=$1; shift
local netem_args="$@"
echo "=== Testing: $desc ==="
# 添加网络条件
tc qdisc add dev lo root netem $netem_args 2>/dev/null
# 运行测试
timeout 30 ./run_integration_tests.sh
local result=$?
# 清除
tc qdisc del dev lo root 2>/dev/null
if [ $result -eq 0 ]; then
echo "PASS: $desc"
else
echo "FAIL: $desc"
fi
return $result
}
# 理想网络
test_under_network_condition "理想网络" delay 0ms
# 局域网
test_under_network_condition "局域网 (1ms)" delay 1ms
# 同城
test_under_network_condition "同城 (5ms)" delay 5ms
# 跨城
test_under_network_condition "跨城 (30ms)" delay 30ms 5ms
# 跨国 + 丢包
test_under_network_condition "跨国 (100ms + 1% loss)" delay 100ms 20ms loss 1%
# 极端条件
test_under_network_condition "极端 (500ms + 5% loss)" delay 500ms 100ms loss 5%六、入口流量控制
6.1 Ingress Policing
tc 主要控制出口(egress)流量。入口(ingress)流量不能整形(因为已经到达),只能丢弃(policing):
# 在 ingress 上限制入口带宽
tc qdisc add dev eth0 handle ffff: ingress
# 限制来自 10.0.0.0/8 的流量不超过 500Mbps
tc filter add dev eth0 parent ffff: protocol ip prio 1 u32 \
match ip src 10.0.0.0/8 \
police rate 500mbit burst 256kb drop \
flowid :1
# 限制 UDP 入口流量(防 DDoS)
tc filter add dev eth0 parent ffff: protocol ip prio 2 u32 \
match ip protocol 17 0xff \
police rate 100mbit burst 128kb drop \
flowid :2
# 查看统计
tc -s filter show dev eth0 parent ffff:6.2 IFB 虚拟设备
要对入口流量做分层控制,需要使用 IFB(Intermediate Functional Block)设备将入口流量重定向到虚拟接口的出口:
# 加载 IFB 模块
modprobe ifb numifbs=1
ip link set ifb0 up
# 将 eth0 入口重定向到 ifb0
tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 \
match u32 0 0 \
action mirred egress redirect dev ifb0
# 在 ifb0 上配置 HTB(与出口相同的方式)
tc qdisc add dev ifb0 root handle 1: htb default 30
tc class add dev ifb0 parent 1: classid 1:1 htb \
rate 1gbit ceil 1gbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb \
rate 500mbit ceil 1gbit prio 1
tc class add dev ifb0 parent 1:1 classid 1:20 htb \
rate 300mbit ceil 500mbit prio 2
tc class add dev ifb0 parent 1:1 classid 1:30 htb \
rate 200mbit ceil 200mbit prio 3
# 分类规则
tc filter add dev ifb0 parent 1: protocol ip prio 1 u32 \
match ip sport 80 0xffff flowid 1:10
tc filter add dev ifb0 parent 1: protocol ip prio 1 u32 \
match ip sport 443 0xffff flowid 1:106.3 cgroup 级别带宽控制
# 使用 cgroup v2 的网络带宽控制
# 在容器/Pod 场景下,结合 cgroup 更精确
# Kubernetes 的带宽限制注解
# metadata:
# annotations:
# kubernetes.io/ingress-bandwidth: "100M"
# kubernetes.io/egress-bandwidth: "50M"
# 对应的 CNI 插件(bandwidth plugin)会自动配置 tc:
# 1. 创建 IFB 设备
# 2. 在 veth 上配置 HTB
# 3. 限制 Pod 的网络带宽七、tc-bpf 可编程流量控制
7.1 eBPF 分类器
# tc-bpf 允许使用 eBPF 程序做流量分类和控制
# 使用 eBPF 做流量分类的优势:
# 1. 灵活性——可以根据任意包内容分类
# 2. 性能——JIT 编译后接近原生速度
# 3. 动态——可以不重启网络栈更新规则
# 加载 eBPF 分类程序
tc qdisc add dev eth0 root handle 1: htb default 30
tc filter add dev eth0 parent 1: bpf obj classifier.o sec tc direct-action
# eBPF 程序可以:
# - 读取包的任意字段(IP/TCP/UDP/HTTP)
# - 根据 Map 中的策略做分类
# - 设置 classid 指向不同 HTB class
# - 修改 DSCP/TOS 字段
# - 直接丢弃或重定向7.2 tc-bpf vs 传统 filter
| 特性 | u32 filter | fw filter | tc-bpf |
|---|---|---|---|
| 匹配能力 | 固定偏移量 | iptables mark | 任意字段 |
| 性能 | 硬编码匹配 | 需 iptables 配合 | JIT 编译 |
| 动态更新 | 需删除重建 | 需更新 iptables | Map 热更新 |
| 复杂逻辑 | 有限 | 有限 | 完整编程 |
| 学习成本 | 低 | 中 | 高 |
# 使用 bpftool 查看已加载的 tc-bpf 程序
bpftool net show
# 查看特定接口的 tc-bpf
tc filter show dev eth0 egress八、QoS 策略设计
8.1 常见 QoS 模型
| 模型 | 特点 | 适用场景 |
|---|---|---|
| 尽力而为(Best Effort) | 无差别对待 | 简单环境 |
| DiffServ | DSCP 标记 + PHB | 企业网络 |
| IntServ | 端到端预留 | 实时通信 |
| 自定义 HTB | 按业务分类 | 服务器出口 |
8.2 DSCP 标记
7.1 常见 QoS 模型
| 模型 | 特点 | 适用场景 |
|---|---|---|
| 尽力而为(Best Effort) | 无差别对待 | 简单环境 |
| DiffServ | DSCP 标记 + PHB | 企业网络 |
| IntServ | 端到端预留 | 实时通信 |
| 自定义 HTB | 按业务分类 | 服务器出口 |
7.2 DSCP 标记
# DSCP(Differentiated Services Code Point)是 IP 头部的 6 位字段
# 用于在网络设备上区分流量优先级
# 常用 DSCP 值
# EF (46) — 加急转发(Expedited Forwarding)— 实时语音/视频
# AF41 (34) — 确保转发 Class 4 — 重要业务
# AF31 (26) — 确保转发 Class 3 — 一般业务
# CS1 (8) — 低优先级 — 后台流量
# 0 — 尽力而为(默认)
# 使用 iptables 标记出口流量
iptables -t mangle -A OUTPUT -p tcp --dport 80 -j DSCP --set-dscp-class EF
iptables -t mangle -A OUTPUT -p tcp --dport 3306 -j DSCP --set-dscp-class AF31
# 在 tc filter 中基于 DSCP 分类
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
match ip tos 0xb8 0xfc flowid 1:10
# 0xb8 = EF (DSCP 46) 左移 2 位参考文献
- Hubert, B. et al., “Linux Advanced Routing & Traffic Control HOWTO,” lartc.org.
- Nichols, K. and Jacobson, V., “Controlling Queue Delay,” ACM Queue, 2012.
- Høiland-Jørgensen, T. et al., “The FlowQueue-CoDel Packet Scheduler and Active Queue Management Algorithm,” RFC 8290, 2018.
- Linux Kernel Documentation, “Traffic Control,” kernel.org/doc/Documentation/networking/tc.rst.
- Hubert, B., “TC manual page,” man tc(8).
- Hemminger, S., “netem — Network Emulator,” kernel.org.
- Hoelzle, U. and Barroso, L., “The Datacenter as a Computer,” Morgan & Claypool, 2018.
九、tc 监控与故障排查
9.1 统计信息解读
# 查看所有 qdisc 的详细统计
tc -s -d qdisc show dev eth0
# 输出示例:
# qdisc htb 1: root r2q 10 default 0x30 direct_packets_stat 0
# Sent 1234567890 bytes 9876543 pkt (dropped 42, overlimits 5678 requeues 12)
# backlog 0b 0p requeues 12
# 关键指标:
# Sent — 已发送的字节数和包数
# dropped — 被丢弃的包数(queue full 或 policing)
# overlimits — 超过限速的次数(包被延迟)
# requeues — 重新入队的次数
# backlog — 当前队列中的字节数和包数
# 查看 class 统计
tc -s class show dev eth0
# 输出示例:
# class htb 1:10 parent 1:1 prio 1 rate 500Mbit ceil 1Gbit burst 256Kb
# Sent 567890123 bytes 4567890 pkt (dropped 0, overlimits 1234 requeues 0)
# rate 450Mbit 365000pps
# lended: 4000000 borrowed: 567890 giants: 0
# tokens: -1234 ctokens: 5678
# lended — 使用自身 rate 发送的包数
# borrowed — 从父 class 借用带宽发送的包数
# giants — 超过 MTU 的包数(不应出现)
# tokens — 当前令牌数(负数表示超支)9.2 实时监控脚本
#!/bin/bash
# tc-monitor.sh — 实时监控 tc 流量分配
DEV=${1:-eth0}
INTERVAL=${2:-1}
echo "监控 $DEV 的 tc 统计(每 ${INTERVAL}s)"
echo "按 Ctrl+C 退出"
echo ""
declare -A prev_bytes
declare -A prev_pkts
while true; do
clear
echo "=== tc 流量统计 $(date '+%H:%M:%S') ==="
echo ""
while IFS= read -r line; do
if [[ $line =~ "class htb" ]]; then
class=$(echo "$line" | grep -o '1:[0-9]*')
rate=$(echo "$line" | grep -o 'rate [0-9]*[KMG]*bit' | head -1)
ceil=$(echo "$line" | grep -o 'ceil [0-9]*[KMG]*bit')
fi
if [[ $line =~ "Sent" ]]; then
bytes=$(echo "$line" | grep -o '[0-9]* bytes' | grep -o '[0-9]*')
pkts=$(echo "$line" | grep -o '[0-9]* pkt' | grep -o '[0-9]*')
dropped=$(echo "$line" | grep -o 'dropped [0-9]*' | grep -o '[0-9]*')
# 计算速率
key="$class"
if [ -n "${prev_bytes[$key]}" ]; then
bps=$(( (bytes - prev_bytes[$key]) * 8 / INTERVAL ))
pps=$(( (pkts - prev_pkts[$key]) / INTERVAL ))
printf "%-8s %s %s 当前: %8s bps %6s pps 丢弃: %s\n" \
"$class" "$rate" "$ceil" \
"$(numfmt --to=si $bps 2>/dev/null || echo $bps)" \
"$pps" "$dropped"
fi
prev_bytes[$key]=$bytes
prev_pkts[$key]=$pkts
fi
done < <(tc -s class show dev $DEV 2>/dev/null)
sleep $INTERVAL
done9.3 常见问题排查
# 问题 1:tc 规则不生效
# 原因:filter 优先级冲突或 classid 不匹配
tc filter show dev eth0 parent 1:
# 检查 prio 和 flowid 是否正确
# 问题 2:overlimits 过高但未丢包
# 正常现象——overlimits 表示包被延迟(整形),不是丢弃
tc -s qdisc show dev eth0 | grep -E "dropped|overlimits"
# 问题 3:带宽没有达到 ceil
# 原因:可能没有足够的流量,或者父 class 没有空闲带宽
tc -s class show dev eth0 | grep "borrowed"
# borrowed 为 0 说明没有成功借用
# 问题 4:所有流量都走 default class
# 原因:filter 规则没有匹配
tc filter show dev eth0 parent 1:
# 确认 filter 的匹配条件正确十、实战案例
10.1 案例一:多租户服务器带宽隔离
场景:一台服务器上运行多个客户的服务,需要保证每个客户的带宽不受其他客户影响。
#!/bin/bash
# tenant-isolation.sh — 多租户带宽隔离
DEV=eth0
TOTAL=10gbit
tc qdisc del dev $DEV root 2>/dev/null
tc qdisc add dev $DEV root handle 1: htb default 99
# 总带宽
tc class add dev $DEV parent 1: classid 1:1 htb \
rate $TOTAL ceil $TOTAL
# 租户 A:保证 3Gbps,最大 5Gbps
tc class add dev $DEV parent 1:1 classid 1:10 htb \
rate 3gbit ceil 5gbit prio 1
tc qdisc add dev $DEV parent 1:10 fq_codel
# 租户 B:保证 3Gbps,最大 5Gbps
tc class add dev $DEV parent 1:1 classid 1:20 htb \
rate 3gbit ceil 5gbit prio 1
tc qdisc add dev $DEV parent 1:20 fq_codel
# 租户 C:保证 2Gbps,最大 3Gbps
tc class add dev $DEV parent 1:1 classid 1:30 htb \
rate 2gbit ceil 3gbit prio 2
tc qdisc add dev $DEV parent 1:30 fq_codel
# 默认(未分类流量):保证 1Gbps
tc class add dev $DEV parent 1:1 classid 1:99 htb \
rate 1gbit ceil 1gbit prio 3
tc qdisc add dev $DEV parent 1:99 fq_codel
# 按源 IP 分类
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip src 10.0.1.0/24 flowid 1:10
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip src 10.0.2.0/24 flowid 1:20
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip src 10.0.3.0/24 flowid 1:30
echo "租户隔离配置完成"
tc -s class show dev $DEV10.2 案例二:API 服务 QoS 保证
场景:API 服务器同时处理在线请求和后台批处理任务。在线请求必须优先,批处理不能抢占在线带宽。
#!/bin/bash
# api-qos.sh — API 流量优先保证
DEV=eth0
tc qdisc del dev $DEV root 2>/dev/null
tc qdisc add dev $DEV root handle 1: htb default 30 r2q 100
tc class add dev $DEV parent 1: classid 1:1 htb \
rate 1gbit ceil 1gbit
# API 响应(高优先级)
tc class add dev $DEV parent 1:1 classid 1:10 htb \
rate 600mbit ceil 1gbit prio 0
tc qdisc add dev $DEV parent 1:10 fq_codel \
target 1ms interval 50ms
# 数据库同步(中优先级)
tc class add dev $DEV parent 1:1 classid 1:20 htb \
rate 300mbit ceil 800mbit prio 2
tc qdisc add dev $DEV parent 1:20 fq_codel
# 批处理/备份(低优先级,严格限制)
tc class add dev $DEV parent 1:1 classid 1:30 htb \
rate 100mbit ceil 300mbit prio 5
tc qdisc add dev $DEV parent 1:30 fq_codel
# API 端口分类
for port in 80 443 8080 8443; do
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip sport $port 0xffff flowid 1:10
done
# 数据库端口
for port in 3306 5432 6379 27017; do
tc filter add dev $DEV parent 1: protocol ip prio 2 u32 \
match ip sport $port 0xffff flowid 1:20
done
echo "API QoS 配置完成"
# 验证:使用 iperf3 测试不同端口的带宽
# 终端 1:iperf3 -s -p 8080
# 终端 2:iperf3 -s -p 9999
# 终端 3:iperf3 -c server -p 8080 # 应获得接近 1Gbps
# 终端 4:iperf3 -c server -p 9999 # 应被限制在 300Mbps10.3 案例三:Bufferbloat 治理
场景:用户反馈”网速测试正常,但视频通话卡顿”。原因是路由器/网关的缓冲区过大,大流量传输填满缓冲区,导致交互流量延迟剧增。
# 诊断 Bufferbloat
# 在进行大文件下载的同时 ping
ping -c 100 gateway
# 无负载:RTT = 1ms
# 有下载:RTT = 200ms ← Bufferbloat
# 治理方案:使用 CAKE
# 关键:bandwidth 设为实际带宽的 90-95%
tc qdisc replace dev eth0 root cake \
bandwidth 950mbit \
besteffort \
wash
# 对于有 NAT 的网关
tc qdisc replace dev eth0 root cake \
bandwidth 950mbit \
nat \
wash
# 效果验证——同时下载时的延迟
ping -c 100 gateway
# 治理前:RTT = 200ms
# 治理后:RTT = 5ms
# 为什么 bandwidth 要设低 5-10%?
# CAKE 通过让自己成为瓶颈来控制队列
# 如果设置等于实际带宽,上游设备的缓冲区仍会膨胀十一、流量整形与容器网络
11.1 Docker 带宽限制
# Docker 本身没有内置带宽限制
# 需要通过 tc 在 veth 设备上配置
# 找到容器的 veth 设备
CONTAINER_ID=$(docker inspect -f '{{.Id}}' my-container)
VETH=$(ip link | grep -oP "veth[a-f0-9]+@" | sed 's/@//' | while read veth; do
ip link show $veth | grep -q "$CONTAINER_ID" && echo $veth
done)
# 或者更简单的方法
PID=$(docker inspect -f '{{.State.Pid}}' my-container)
nsenter -t $PID -n ip link show eth0
# 对应宿主机上的 veth 设备
# 在 veth 上配置限速
tc qdisc add dev $VETH root tbf \
rate 100mbit burst 256kb latency 50ms11.2 Kubernetes 带宽限制
# Pod 级别的带宽限制(通过 CNI bandwidth 插件)
apiVersion: v1
kind: Pod
metadata:
name: bandwidth-limited-pod
annotations:
kubernetes.io/ingress-bandwidth: "100M"
kubernetes.io/egress-bandwidth: "50M"
spec:
containers:
- name: app
image: nginx# 验证 Pod 的带宽限制
# 进入 Pod 所在节点
kubectl get pod bandwidth-limited-pod -o wide # 获取节点
# 找到 Pod 的 veth
VETH=$(ip link | grep -B1 "$(kubectl get pod bandwidth-limited-pod \
-o jsonpath='{.metadata.uid}' | cut -c1-8)" | head -1 | awk '{print $2}' | tr -d ':')
# 查看 tc 规则
tc qdisc show dev $VETH
# 应该看到 HTB + IFB 配置上一篇: 网络延迟优化:Nagle、TCP_NODELAY 与中断亲和 下一篇: 网络性能监控体系:指标、探针与告警
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【网络工程】网络模拟与测试:netem、Mininet 与混沌工程
生产环境的网络条件远比实验室复杂——延迟抖动、随机丢包、带宽突变、链路故障。本文系统讲解 tc netem 的完整用法、Mininet 虚拟网络拓扑搭建、网络层混沌工程(Toxiproxy/Comcast/tc-netem)的实战方法,以及如何在 CI/CD 流水线中集成网络条件测试,确保应用在恶劣网络下的鲁棒性。
【网络工程】MQTT 工程:IoT 协议的 QoS 与 MQTT 5.0
系统剖析 MQTT 协议的工程实践:连接管理、Clean Session 与 Persistent Session、三种 QoS 级别的消息流与可靠性、Retained Message、Last Will、MQTT 5.0 新特性、Broker 架构设计。
【Linux 网络子系统深度拆解】Traffic Control 深度拆解:qdisc、class 与 filter
dev_queue_xmit() 不是直接把包交给网卡——中间还有一层 Traffic Control。本文从 Linux 6.6 内核源码拆解 TC 框架的完整实现:struct Qdisc 与 Qdisc_ops 操作表、pfifo_fast/fq_codel/HTB/TBF 的内核实现差异、TCQ_F_CAN_BYPASS 快路径、TCQ_F_NOLOCK 无锁排队、EDT(Earliest Departure Time)调度模型、TC BPF direct-action 模式,以及 MQ 多队列根 qdisc 与 netdev_queue 的关系。
网络工程索引
汇总本站网络工程系列文章,覆盖分层模型、以太网、IP、TCP、DNS、TLS、HTTP/2/3、CDN、BGP 与故障诊断。