Linux流量控制神器TC完全指南:原理详解与实践指南

网络流量控制从未如此清晰,从内核原理到生产环境实战

引言

在日常开发和运维中,你是否遇到过这些情况?

  • Git拉取代码时,整个办公室网络都被拖慢
  • 数据库同步占满带宽,影响线上服务
  • 需要为不同业务分配不同的网络优先级
  • 防止某些IP地址滥用网络资源

所有这些问题的解决方案,都指向Linux内核中一个强大而神秘的工具------TC(Traffic Control,流量控制)。本文将深入浅出地讲解TC的原理、核心概念,并通过实际案例展示如何应用它解决各种网络流量管理问题。

一、TC原理:Linux内核流量控制的核心

1.1 TC在网络栈中的位置

TC是Linux内核实现流量控制的核心机制。要理解TC,首先要明白它在网络数据包处理流程中的位置:

复制代码
接收包 → 流量限制 → 输入多路分配器 → 本机处理 或 转发处理

具体来说:

  1. 接收阶段:数据包从网络接口进入,TC首先进行流量限制,丢弃不符合规定的包

  2. 分发决策:经过输入多路分配器判断:

    • 目的地址是本机 → 送往上层协议栈(TCP/UDP)
    • 目的地址是其他主机 → 进入转发流程
  3. 发送控制:这是TC发挥作用的主要环节,对出站(egress)流量进行队列管理和整形

关键点 :TC主要控制发送(egress)流量,而非接收(ingress)流量。这是因为在发送端控制更为有效和直接。

1.2 为什么TC如此重要?

  • 公平性:防止单一连接独占带宽
  • 服务质量:保证关键业务的网络质量
  • 带宽管理:合理分配有限的网络资源
  • 流量整形:平滑突发流量,避免网络拥塞

二、TC核心概念解析

2.1 四种流量控制方式

TC提供了四种基本的流量控制方式:

方式 作用方向 描述
SHAPING(限制) 出向 平滑流量,限制峰值速率,类似"水坝"
SCHEDULING(调度) 出向 按优先级分配带宽,类似"交通信号灯"
POLICING(策略) 入向 检查入站流量,丢弃违规包
DROPPING(丢弃) 双向 超出限制时直接丢弃数据包

2.2 三大核心对象

TC的配置围绕三个核心对象展开,理解它们的关系至关重要:

python 复制代码
qdisc 队列规则--> class 类别1 --> filter 过滤器1
   |                 | --> filter 过滤器2
   |--> C[class 类别2] --> filter 过滤器3

2.2.1 qdisc(排队规则)

qdisc是流量控制的基础,每个网络接口都必须有一个qdisc(默认为pfifo_fast)。

不可分类qdisc(简单队列):

bash 复制代码
# 创建FIFO队列(基于包数量)
tc qdisc add dev eth0 root pfifo limit 100

# 创建FIFO队列(基于字节数)
tc qdisc add dev eth0 root bfifo limit 10mbit
类型 描述 适用场景
pfifo_fast 默认qdisc,三个优先级波段 一般用途
sfq(随机公平队列) 按会话(session)循环调度 保证多个TCP连接的公平性
tbf(令牌桶过滤器) 精确控制速率 需要稳定速率的场景

可分类qdisc(高级队列):

csharp 复制代码
# HTB(分层令牌桶)- 推荐使用
tc qdisc add dev eth0 root handle 1: htb default 30

# CBQ(基于类别的排队)
tc qdisc add dev eth0 root handle 1: cbq bandwidth 100Mbit avpkt 1000

2.2.2 class(类)

在可分类qdisc中,可以创建多个class实现精细控制:

kotlin 复制代码
# 创建HTB根类
tc class add dev eth0 parent 1: classid 1:1 htb rate 100Mbit

# 创建子类
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30Mbit ceil 50Mbit
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 20Mbit ceil 30Mbit

参数说明

  • rate:保证带宽,必须满足
  • ceil:最大带宽,可借用空闲带宽
  • burst:突发流量容量

2.2.3 filter(过滤器)

过滤器决定数据包进入哪个class:

python 复制代码
# 基于端口过滤
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10

# 基于IP地址过滤
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.1.0/24 flowid 1:20

2.3 流量分类的三种方式

  1. tc filter:最灵活,支持各种匹配条件
  2. 服务类型(ToS) :根据IP头部的ToS字段
  3. skb->priority:应用程序通过socket选项设置

三、TC命令完全指南

3.1 基本命令格式

css 复制代码
tc [选项] 对象 命令 设备 参数

对象类型

  • qdisc:排队规则
  • class:类别
  • filter:过滤器

常用命令

命令 描述 示例
add 添加规则 tc qdisc add dev eth0 root htb
del 删除规则 tc qdisc del dev eth0 root
change 修改规则 tc class change dev eth0 parent 1: classid 1:1 htb rate 50Mbit
replace 替换规则 tc filter replace dev eth0 parent 1:0 protocol ip u32 match ip dst 192.168.1.1 flowid 1:10
show 显示规则 tc -s qdisc show dev eth0

3.2 单位换算要点

常见错误:混淆 bit(比特)和 Byte(字节)

ini 复制代码
# 正确示例
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1mbit  # 1 Mbps = 125 KB/s
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 1024kbit  # 1024 Kbps = 128 KB/s

# 带宽单位换算
1 Gbit = 1000 Mbit = 1000000 Kbit
1 GB = 1024 MB = 1048576 KB
1 Byte = 8 bits

四、实战应用:从入门到精通

4.1 Git仓库限速方案

场景:Git拉取代码占满带宽,影响其他业务

方案一:基于端口限速(Git over SSH)

bash 复制代码
#!/bin/bash
# git-limit-port.sh
# Git SSH端口(22)限速方案

DEV="eth0"
RATE="1mbit"  # 限制为1 Mbps
CEIL="1.5mbit"  # 最大1.5 Mbps
BURST="15k"

# 清理现有规则
tc qdisc del dev $DEV root 2>/dev/null

# 创建HTB队列
tc qdisc add dev $DEV root handle 1: htb default 999

# 创建默认类别(不限速)
tc class add dev $DEV parent 1: classid 1:999 htb rate 1000mbit ceil 1000mbit

# 创建限速类别
tc class add dev $DEV parent 1: classid 1:10 htb rate $RATE ceil $CEIL burst $BURST

# 添加SFQ防止单一连接独占
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10

# 创建过滤器:Git SSH端口(22)进入限速类别
tc filter add dev $DEV protocol ip parent 1: prio 1 u32 \
  match ip sport 22 0xffff flowid 1:10

# 其他所有流量走默认类别
tc filter add dev $DEV protocol ip parent 1: prio 2 u32 \
  match ip dst 0.0.0.0/0 flowid 1:999
  
echo "Git SSH限速已设置:${RATE},保存到/etc/rc.local实现开机自启"

方案二:基于IP地址限速

bash 复制代码
#!/bin/bash
# git-limit-ip.sh
# 针对特定IP的Git限速

DEV="eth0"
GIT_SERVER="github.com"  # 可替换为实际Git服务器IP
LIMIT_RATE="512kbit"    # 限制速率
MAX_RATE="1mbit"        # 最大速率
LOCAL_NET="192.168.1.0/24"  # 内网网段

# 获取Git服务器IP(如果使用域名)
GIT_IP=$(dig +short $GIT_SERVER | head -1)
[ -z "$GIT_IP" ] && GIT_IP="192.168.1.100"  # 备用IP

# 清理规则
tc qdisc del dev $DEV root 2>/dev/null

# 创建HTB队列
tc qdisc add dev $DEV root handle 1: htb default 9999

# 创建根类(总带宽100Mbps)
tc class add dev $DEV parent 1: classid 1:1 htb rate 100mbit

# 创建各类别
# 1. Git服务器限速
tc class add dev $DEV parent 1:1 classid 1:10 htb rate $LIMIT_RATE ceil $MAX_RATE burst 15k
# 2. 内网不限速
tc class add dev $DEV parent 1:1 classid 1:20 htb rate 90mbit ceil 100mbit burst 15k
# 3. 其他流量
tc class add dev $DEV parent 1:1 classid 1:9999 htb rate 10mbit ceil 100mbit burst 15k

# 为每个类别添加SFQ
for classid in 10 20 9999; do
  tc qdisc add dev $DEV parent 1:$classid handle ${classid}0: sfq perturb 10
done

# 设置过滤器(注意优先级prio)
# 规则1:内网不限速(最高优先级)
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
  match ip dst $LOCAL_NET flowid 1:20
  
# 规则2:Git服务器限速
tc filter add dev $DEV parent 1: protocol ip prio 2 u32 \
  match ip dst $GIT_IP flowid 1:10
  
# 规则3:默认规则
tc filter add dev $DEV parent 1: protocol ip prio 3 u32 \
  match ip dst 0.0.0.0/0 flowid 1:9999
  
echo "Git IP限速配置完成"
echo "Git服务器: $GIT_IP 限速: $LIMIT_RATE"
echo "内网网段: $LOCAL_NET 不限速"

关键技巧

  • 过滤器优先级(prio)很重要,数字越小优先级越高
  • 内网规则应该放在前面(prio值小)
  • 使用sfq防止单个连接独占带宽

4.2 生产环境多主机流量控制

场景:为不同服务器分配不同带宽

bash 复制代码
#!/bin/bash
# multi-host-limit.sh
# 为不同目标主机分配不同带宽

DEV="eth0"
TOTAL_BW="10mbit"

# 目标主机及带宽配置
declare -A HOSTS=(
  ["192.168.1.10"]="3mbit"  # 数据库服务器
  ["192.168.1.20"]="2mbit"  # 文件服务器  
  ["192.168.1.30"]="1mbit"  # 监控服务器
)

# 清理并初始化
tc qdisc del dev $DEV root 2>/dev/null
tc qdisc add dev $DEV root handle 1: htb default 999
tc class add dev $DEV parent 1: classid 1:1 htb rate $TOTAL_BW

# 为每个主机创建类别
CLASS_ID=10
for HOST in "${!HOSTS[@]}"; do
  BW=${HOSTS[$HOST]}
  tc class add dev $DEV parent 1:1 classid 1:$CLASS_ID htb rate $BW ceil $BW burst 15k
  tc qdisc add dev $DEV parent 1:$CLASS_ID handle ${CLASS_ID}0: sfq perturb 10
  tc filter add dev $DEV parent 1: protocol ip prio 5 u32 \
    match ip dst $HOST flowid 1:$CLASS_ID
  ((CLASS_ID++))
done

# 默认类别
tc class add dev $DEV parent 1:1 classid 1:999 htb rate 4mbit ceil 4mbit
tc qdisc add dev $DEV parent 1:999 handle 9990: sfq perturb 10

4.3 MySQL数据库同步限速

场景:数据库主从同步不影响线上业务

bash 复制代码
#!/bin/bash
# mysql-sync-limit.sh
# MySQL双向同步限速方案

# 节点配置
LOCAL_IP="10.9.57.162"
PEER_IP="10.12.1.45"
LIMIT_RATE="8mbit"  # 限制为8 Mbps
DEV="eth0"

# 本机限速配置
tc qdisc add dev $DEV root handle 1: htb default 1
tc class add dev $DEV parent 1: classid 1:1 htb rate 1000mbit
tc class add dev $DEV parent 1:1 classid 1:10 htb rate $LIMIT_RATE ceil $LIMIT_RATE burst 15k
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc filter add dev $DEV parent 1: protocol ip prio 1 u32 \
  match ip dst $PEER_IP flowid 1:10

echo "MySQL同步限速配置完成:$LIMIT_RATE"

五、监控与调试

5.1 查看TC配置

python 复制代码
# 查看队列状态
tc -s qdisc show dev eth0

# 查看类别状态
tc -s class show dev eth0

# 查看过滤器
tc -s filter show dev eth0

# 详细统计信息
tc -s -d qdisc show dev eth0
tc -s -d class show dev eth0

5.2 关键指标解读

csharp 复制代码
# 示例输出
qdisc htb 1: root refcnt 2 r2q 10 default 1 direct_packets_stat 0 ver 3.17
 Sent 123456 bytes 789 pkt (dropped 0, overlimits 0 requeues 0) 
 backlog 0b 0p requeues 0
  • Sent:发送的数据量和包数
  • dropped:丢弃的包数,非零表示有丢包
  • overlimits:超过限制的次数
  • backlog:队列中积压的数据

5.3 带宽测试方法

csharp 复制代码
# 安装测速工具
yum install -y iperf3  # CentOS
apt-get install -y iperf3  # Ubuntu

# 服务器端
iperf3 -s

# 客户端
iperf3 -c 服务器IP -t 30 -P 10

# 简单的网络测试
speedtest-cli  # 测试公网带宽
tcpping 目标IP  # 测试延迟和抖动

六、高级技巧与最佳实践

6.1 动态调整带宽

bash 复制代码
#!/bin/bash
# dynamic-bandwidth.sh
# 根据时间动态调整带宽

DEV="eth0"
DAY_RATE="100mbit"
NIGHT_RATE="20mbit"

adjust_bandwidth() {
  HOUR=$(date +%H)
  
  if [ $HOUR -ge 8 ] && [ $HOUR -lt 20 ]; then
    RATE=$DAY_RATE
    echo "工作时间:设置带宽为 $DAY_RATE"
  else
    RATE=$NIGHT_RATE
    echo "非工作时间:设置带宽为 $NIGHT_RATE"
  fi
  
  # 调整默认类别带宽
  tc class change dev $DEV parent 1: classid 1:999 htb rate $RATE ceil $RATE
  
  # 记录日志
  echo "$(date): 带宽调整为 $RATE" >> /var/log/tc-adjust.log
}

# 添加到crontab,每小时执行一次
# 0 * * * * /path/to/dynamic-bandwidth.sh

6.2 多网卡负载均衡

bash 复制代码
#!/bin/bash
# multi-wan-balance.sh
# 多WAN口负载均衡与限速

WAN1="eth1"
WAN2="eth2"
TOTAL_BW="200mbit"

# 为每个WAN口设置HTB
for DEV in $WAN1 $WAN2; do
  tc qdisc add dev $DEV root handle 1: htb default 1
  tc class add dev $DEV parent 1: classid 1:1 htb rate $(($TOTAL_BW/2))mbit
  
  # 为不同服务分配带宽
  tc class add dev $DEV parent 1:1 classid 1:10 htb rate 20mbit ceil 30mbit  # HTTP
  tc class add dev $DEV parent 1:1 classid 1:20 htb rate 10mbit ceil 20mbit  # SSH
  tc class add dev $DEV parent 1:1 classid 1:30 htb rate 50mbit ceil 70mbit  # 默认
  
  # 添加过滤器
  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 2 u32 \
    match ip dport 22 0xffff flowid 1:20
done

七、常见问题与解决方案

Q1: TC规则重启后丢失?

A: 将配置保存到启动脚本

ini 复制代码
# CentOS/RHEL
echo "/path/to/tc-script.sh" >> /etc/rc.local
chmod +x /etc/rc.local

# 或者使用systemd
cat > /etc/systemd/system/tc-traffic-control.service << EOF
[Unit]
Description=Traffic Control Service
After=network.target

[Service]
Type=oneshot
ExecStart=/path/to/tc-script.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

Q2: 如何查看实时流量?

ini 复制代码
# 使用iftop查看实时流量
iftop -i eth0 -n

# 使用nethogs查看进程流量
nethogs eth0

# TC监控脚本
watch -n 1 "tc -s qdisc show dev eth0; echo '---'; tc -s class show dev eth0"

Q3: 限速不生效?

  1. 检查单位:确保使用正确的单位(mbit vs mbyte)
  2. 检查设备:确保在正确的网络接口上配置
  3. 检查方向:TC主要控制出站(egress)流量
  4. 检查优先级:过滤器的prio值可能影响匹配顺序

八、总结

TC是Linux系统中强大的流量控制工具,虽然学习曲线较陡峭,但一旦掌握,就能精细控制网络流量。关键点:

  1. 理解架构:qdisc-class-filter三级结构
  2. 选对队列:HTB适合大多数场景,简单且功能强大
  3. 精细分类:根据业务需求创建合理的类别
  4. 正确过滤:使用u32或fw等过滤器精确匹配流量
  5. 监控调试:通过统计信息验证效果,及时调整

通过合理的TC配置,可以实现:

  • 关键业务带宽保障
  • 防止带宽滥用
  • 提高网络稳定性
  • 优化用户体验
相关推荐
Java陈序员几秒前
运维必备!一款全平台可用的服务器管理利器!
linux·react.js·docker
oMcLin1 分钟前
如何在Oracle Linux 8.5上配置并优化Oracle RAC集群,确保企业级数据库的高可用性与负载均衡?
linux·数据库·oracle
威桑1 分钟前
交叉编译过程中的踩坑与收获
linux·c++·arm·交叉编译
HIT_Weston7 分钟前
90、【Ubuntu】【Hugo】搭建私人博客:侧边导航栏(四)
linux·运维·ubuntu
回忆是昨天里的海9 分钟前
dockerfile-镜像分层机制
linux·运维·服务器
chen_mangoo28 分钟前
Rockchip debian预置安装deb包
linux·驱动开发·嵌入式硬件
雪风飞舞29 分钟前
conda 常用命令
linux·windows·conda
用户747122011698331 分钟前
linux最小版本编译-草稿(有空再来修改下)
linux
Xの哲學35 分钟前
Linux Select 工作原理深度剖析: 从设计思想到实现细节
linux·服务器·网络·算法·边缘计算
VekiSon36 分钟前
综合项目实战——电子商城信息查询系统
linux·c语言·网络·http·html·tcp·sqlite3