土法炼钢兴趣小组的算法知识备份

【网络工程】带宽管理与流量整形:tc、QoS 与拥塞管理

文章导航

分类入口
network
标签入口
#traffic-shaping#tc#qos#htb#fq-codel#bandwidth-management#netem

目录

你的 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 $DEV

3.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 5

4.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, paretonormal

5.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 root

5.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:10

6.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 位

参考文献

  1. Hubert, B. et al., “Linux Advanced Routing & Traffic Control HOWTO,” lartc.org.
  2. Nichols, K. and Jacobson, V., “Controlling Queue Delay,” ACM Queue, 2012.
  3. Høiland-Jørgensen, T. et al., “The FlowQueue-CoDel Packet Scheduler and Active Queue Management Algorithm,” RFC 8290, 2018.
  4. Linux Kernel Documentation, “Traffic Control,” kernel.org/doc/Documentation/networking/tc.rst.
  5. Hubert, B., “TC manual page,” man tc(8).
  6. Hemminger, S., “netem — Network Emulator,” kernel.org.
  7. 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
done

9.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 $DEV

10.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   # 应被限制在 300Mbps

10.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 50ms

11.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 与中断亲和 下一篇: 网络性能监控体系:指标、探针与告警

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2025-08-07 · network

【网络工程】网络模拟与测试:netem、Mininet 与混沌工程

生产环境的网络条件远比实验室复杂——延迟抖动、随机丢包、带宽突变、链路故障。本文系统讲解 tc netem 的完整用法、Mininet 虚拟网络拓扑搭建、网络层混沌工程(Toxiproxy/Comcast/tc-netem)的实战方法,以及如何在 CI/CD 流水线中集成网络条件测试,确保应用在恶劣网络下的鲁棒性。

2026-04-23 · linux / networking

【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 的关系。

2026-04-22 · network

网络工程索引

汇总本站网络工程系列文章,覆盖分层模型、以太网、IP、TCP、DNS、TLS、HTTP/2/3、CDN、BGP 与故障诊断。


By .