5593 字
28 分钟
Linux使用tc模块实现网络限速

Linux使用tc模块实现网络限速#

核心操作速查#

CentOS 针对网卡限速

############# TBF 简单限速
# 清除现有规则
sudo tc qdisc del dev eth0 root 2>/dev/null
# 添加 TBF 规则(限速 400mbit)
sudo tc qdisc add dev eth0 root tbf rate 400mbit latency 50ms burst 25mbit
# sudo tc qdisc add dev eth0 root tbf \
#    rate 400mbit \        # 目标速率
#    burst 25mbit \        # 突发流量桶大小(允许短时间内超出限速值的流量突发)
#    latency 50ms          # 最大延迟
# 查看现有规则
sudo tc qdisc show dev eth0


############# HTB 进阶限速(支持定制多层规则)(推荐使用)
# 清除现有所有规则
sudo tc qdisc del dev eth0 root 2>/dev/null
# 创建限速队列
sudo tc qdisc add dev eth0 root handle 1: htb default 10
# 创建父类,最大带宽区间(1024mbit)
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 1024mbit ceil 1024mbit
# 创建子类,具体限速区间(400mbit)
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 400mbit ceil 400mbit
# 查看现有规则
sudo tc qdisc show dev eth0   #查看队列
sudo tc class show dev eth0   #查看类
## sudo tc class show dev eth0
## class htb 1:10 parent 1:1 prio 0 rate 400Mbit ceil 400Mbit burst 1600b cburst 1600b 
## class htb 1:1 root rate 1024Mbit ceil 1024Mbit burst 1408b cburst 1408b 
## 重点关注指标:
##   rate:保证带宽使用率
##   ceil:最大带宽限制
# 修改现有类
sudo tc class change dev eth0 parent 1: classid 1:1 htb rate 400mbit ceil 400mbit   #修改父类
sudo tc class change dev eth0 parent 1:1 classid 1:10 htb rate 400mbit ceil 400mbit   #修改子类

关于TBF中burst参数的详细说明与最佳设置指南(点击跳转)


Tc详细笔记#

一、TC原理#

Linux操作系统中的流量控制器TC(Traffic Control)用于Linux内核的流量控制,主要是通过在输出端口处建立一个队列来实现流量控制。 接收包从输入接口进来后,经过流量限制丢弃不符合规定的数据包,由输入多路分配器进行判断选择:

  • 如果接收包的目的主机是本主机,那么将该包送给上层处理,否则需要进行转发,将接收包交到转发块(Forwarding Block)处理。
  • 转发块同时也接收本主机上层(TCP、UDP等)产生的包,通过查看路由表,决定所处理包的下一跳。
  • 然后,对包进行排列以便将它们送到输出接口。

一般只能限制网卡发送的数据包,不能限制网卡接收的数据包,所以可以通过改变发送次序来控制传输速率。Linux流量控制主要是在输出接口排列时进行处理和实现的。

二、安装TC#

以下是各主流 Linux 系统安装 tc 命令的方法总结(tc 属于 iproute2 软件包,主要用于网络流量控制):

📦 1、通过包管理器安装#

发行版安装命令验证命令说明
Debian/Ubuntusudo apt update && sudo apt install iproute2tc -Vtc -s基础包已包含 tc
CentOS/RHELsudo yum install iproutesudo yum install iproute-tctc -VCentOS 8+ 需用 iproute-tc
Fedorasudo dnf install iproute2tc -V
Arch Linuxsudo pacman -S iproute2tc -V
Alpine Linuxsudo apk add iproute2tc -V

⚙️ 2、特殊安装方式#

  1. 源码编译安装(适用于嵌入式或自定义环境):

    • 下载源码:wget https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/iproute2-5.9.0.tar.gz
    • 解压并编译:
      tar zxvf iproute2-*.tar.gz
      cd iproute2-*
      ./configure --prefix=/自定义安装路径
      make && sudo make install
    • 依赖:需安装内核头文件及 libxtables 库(部分环境需交叉编译)。
  2. Docker 容器内使用

    docker run -it --privileged ubuntu:latest
    apt update && apt install iproute2  # 在容器内安装
    tc [选项]  # 使用命令

    ⚠️ 需 --privileged 权限以访问主机网络栈。

三、规则#

1、流量控制方式#

流量控制包括以下几种方式:

  • SHAPING(限制): 当流量被限制,它的传输速率就被控制在某个值以下。限制值可以大大小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。
  • SCHEDULING(调度): 通过调度数据包的传输,可以在带宽范围内,按优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。
  • POLICING(策略):SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。
  • DROPPING(丢弃): 如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。

2、流量控制处理对象#

流量的处理由三种对象控制,它们是:

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

1. qdisc(排队规则)#

QDisc(排队规则)是queueing discipline的简写,它是理解流量控制(traffic control)的基础。无论何时,内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的qdisc(排队规则)把数据包加入队列。然后,内核会尽可能多地从qdisc里面取出数据包,把它们交给网络适配器驱动模块。最简单的QDisc是pfifo它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。不过,它会保存网络接口一时无法处理的数据包。

qdisc的类别如下:

CLASSLESS QDisc(不可分类QDisc)

  • [p|b]fifo:使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来设置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数为单位。
  • pfifo_fast:在编译内核时,如果打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。如果band0里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。
  • red:red是Random Early Detection(随机早期探测)的简写。如果使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高带宽应用。
  • sfq:sfq是Stochastic Fairness Queueing的简写。它按照会话(session—对应于每个TCP连接或者UDP流)为流量进行排序,然后循环发送每个会话的数据包。
  • tbf:tbf是Token Bucket Filter的简写,适合于把流速降低到某个值。

CLASSFUL QDISC(分类QDisc)

  • CBQ: CBQ是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。
  • HTB: HTB是Hierarchy Token Bucket的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,它也允许特定的类可以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。
  • PRIO: PRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用iptables或者ipchains处理数据包的服务类型(Type Of Service,ToS)。

2. class(类)#

某些QDisc(排队规则)可以包含一些类别,不同的类别中可以包含更深入的QDisc(排队规则),通过这些细分的QDisc还可以为进入的队列的数据包排队。通过设置各种类别数据包的离队次序,QDisc可以为设置网络数据流量的优先级。

3. filter(过滤器)#

Filter(过滤器)用于为数据包分类,决定它们按照何种QDisc进入队列。无论何时数据包进入一个划分子类的类别中,都需要进行分类。分类的方法可以有多种,使用fileter(过滤器)就是其中之一。使用filter(过滤器)分类时,内核会调用附属于这个类(class)的所有过滤器,直到返回一个判决。如果没有判决返回,就作进一步的处理,而处理方式和QDISC有关。需要注意的是,filter(过滤器)是在QDisc内部,它们不能作为主体。

3、执行过程#

类(Class)组成一个树,每个类都只有一个父类,而一个类可以有多个子类。某些QDisc(例如:CBQ和HTB)允许在运行时动态添加类,而其它的QDisc(例如:PRIO)不允许动态建立类。允许动态添加类的QDisc可以有零个或者多个子类,由它们为数据包排队。此外,每个类都有一个叶子QDisc,默认情况下,这个叶子QDisc使用pfifo的方式排队,我们也可以使用其它类型的QDisc代替这个默认的QDisc。而且,这个叶子QDisc有可以分类,不过每个子类只能有一个叶子QDisc。 当一个数据包进入一个分类QDisc,它会被归入某个子类。 我们可以使用以下三种方式为数据包归类,不过不是所有的QDisc都能够使用这三种方式:

  • tc过滤器(tc filter): 如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由ipchains或者iptables做的标记。
  • 服务类型(Type of Service): 某些QDisc有基于服务类型(Type of Service,ToS)的内置的规则为数据包分类。
  • skb->priority: 用户空间的应用程序可以使用SO_PRIORITY选项在skb->priority域设置一个类的ID。 树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以直接用于其子类。如果数据包没有被成功归类,就会被排到这个类的叶子QDisc的队中。相关细节在各个QDisc的手册页中。

4、命名规则#

所有的QDisc、类和过滤器都有ID。ID可以手工设置,也可以有内核自动分配。ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。

  • qdisc: 一个QDisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间。句柄采用象10:一样的表达方式。习惯上,需要为有子类的QDisc显式地分配一个句柄。
  • class:在同一个QDisc里面的类分享这个QDisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只与父QDisc有关,和父类无关。类的命名习惯和QDisc的相同。
  • filter:过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。详情请参考tc-filters手册页。

5、单位#

带宽或流速单位:

  • kbps : 千字节/s(KB)
  • mbps : 兆字节/s(MB)
  • kbit : Kbit/s(Kb)
  • mbit : Mbit/s(Mb)
  • bps或者一个无单位数字 : 字节/s

数据数量单位:

  • kb或者k : 千字节(KB)
  • mb或者m : 兆字节(MB)
  • kbit : 千bit(Kb)
  • mbit : 兆bit(Mb)
  • b或者一个无单位数字 : 字节数
TIP

1.bit(比特)
2.Byte(字节)
字节 Byte 和比特 bit 的换算关系是 1 Byte = 8 bit 。
我们通常按b的大小写来区分,但是tc参数全是小写,容易导致认错,注意 。

四、tc命令参数解读#

tc可以使用以下命令对QDisc、类和过滤器进行操作:

  • add:在一个节点里加入一个QDisc、类或者过滤器。添加时,需要传递一个祖先作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如果要建立一个QDisc或者过滤器,可以使用句柄(handle)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。
  • remove|del:删除有某个句柄(handle)指定的QDisc,根QDisc(root)也可以删除。被删除QDisc上的所有子类以及附属于各个类的过滤器都会被自动删除。
  • change:以替代的方式修改某些条目。除了句柄(handle)和祖先不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能一定节点的位置。
  • replace:对一个现有节点进行近于原子操作的删除/添加。如果节点不存在,这个命令就会建立节点。
  • link:只适用于DQisc,替代一个现有的节点。

五、实用配置示例#

1、实例:区分内外网,外网限速内网不限速#

#创建队列 指定默认规则11
sudo tc qdisc add dev eth0 root handle 1:0 htb default 11

#创建父规则 最大限制 3G-5G
sudo tc class add dev eth0 parent 1:0 classid 1:1 htb rate 3000mbit ceil 5000mbit

#创建内网规则 放开限制 2G-3G
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 2000mbit ceil 3000mbit

#创建默认规则 即外网规则 限速 20mbit
sudo tc class add dev eth0 parent 1:1 classid 1:11 htb rate 20mbit ceil 20mbit

#指定内网ip段走内网不限速规则
sudo tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.11.0/24 flowid 1:10

#删除队列
sudo tc qdisc del dev eth0 root

#修改规则
sudo tc class change dev eth0 parent 1:1 classid 1:10 htb rate 10mbit ceil 10mbit
sudo tc class change dev eth0 parent 1:1 classid 1:11 htb rate 10mbit ceil 10mbit

#查看规则
sudo tc qdisc show dev eth0 #查看队列
sudo tc class show dev eth0 #查看类

2、进阶:针对某个服务端口限速#

假设我们需要针对 80 端口限速

# 使用iptables给指定端口打上标记
## iptables -t mangle -D OUTPUT -p all --sport ${Port} -j MARK --set-mark 10
## ip6tables -t mangle -D OUTPUT -p all --sport ${Port} -j MARK --set-mark 10
sudo iptables -t mangle -D OUTPUT -p tcp --sport 80 -j MARK --set-mark 10
sudo iptables -t mangle -D OUTPUT -p udp --sport 80 -j MARK --set-mark 10
sudo ip6tables -t mangle -D OUTPUT -p tcp --sport 80 -j MARK --set-mark 10
sudo ip6tables -t mangle -D OUTPUT -p udp --sport 80 -j MARK --set-mark 10

# 创建tc限速规则
## 创建HTB队列
sudo tc qdisc add dev eth0 root handle 1:0 htb
## 创建限速类(限速10mbit)
sudo tc class add dev eth0 parent 1:0 classid 1:1 htb rate 10mbit ceil 10mbit
## 创建过滤器规则(以 IP 协议进行过滤,并把将匹配的10标记数据包发送到类别 ID 为 1:1 的类中)
sudo tc filter add dev eth0 parent 1:0 protocol all handle 10 fw flowid 1:1

3、场景:企业网络 QoS#

# 创建根队列
sudo tc qdisc add dev eth0 root handle 1: htb default 40

# 总带宽池 (1Gbps)
sudo tc class add dev eth0 parent 1: classid 1:1 htb \
    rate 1000mbit ceil 1000mbit

# 关键业务 (VoIP/视频会议)
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb \
    rate 200mbit ceil 300mbit prio 1  # 高优先级

# 常规业务 (网页/邮件)
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb \
    rate 300mbit ceil 600mbit prio 2

# 大流量业务 (文件下载)
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb \
    rate 200mbit ceil 800mbit prio 3

# 默认类 (未知流量)
sudo tc class add dev eth0 parent 1:1 classid 1:40 htb \
    rate 100mbit ceil 200mbit prio 4

其他记录#

HTB ceil 参数详解#

在 Linux 流量控制(tc)的 HTB(Hierarchical Token Bucket)队列规则中,ceil 是一个关键参数,它定义了类(class)可以借用的最大带宽上限。理解 ceil 对于构建灵活高效的 QoS 策略至关重要。

ceil 的核心作用#

基本概念#

参数描述
rate保证带宽(Guaranteed Bandwidth)
该类必须获得的最低带宽
ceil最大可借用带宽(Ceiling Bandwidth)
该类可以借用的最高带宽

工作原理#

graph LR
    A[父类带宽池] -->|rate 保证| B[子类1]
    A -->|rate 保证| C[子类2]
    A -->|空闲带宽| B
    A -->|空闲带宽| C
    B -.->|ceil 限制| D[最大带宽]
    C -.->|ceil 限制| E[最大带宽]
  • 当类使用带宽低于 rate 时:只使用自己的保证带宽
  • 当类需要更多带宽时:
    1. 检查父类是否有空闲带宽
    2. 如果空闲带宽可用,可以借用
    3. 但总带宽不能超过 ceil

配置语法#

tc class add dev [设备] parent [父类ID] classid [类ID] htb \
    rate [保证带宽] \
    ceil [最大带宽]

关键特性#

1. 带宽借用机制#

# 示例:Web服务保证50Mbps,最高可借用至100Mbps
tc class add dev eth0 parent 1:1 classid 1:10 htb \
    rate 50mbit \
    ceil 100mbit
  • 当其他类空闲时,该类可临时使用 100Mbps
  • 当其他类需要带宽时,必须归还借用的部分(不低于 50Mbps)

2. 分层限制#

# 父类总带宽 200Mbps
tc class add dev eth0 parent 1: classid 1:1 htb \
    rate 200mbit ceil 200mbit

# 子类A:保证100Mbps,最高150Mbps
tc class add dev eth0 parent 1:1 classid 1:10 htb \
    rate 100mbit ceil 150mbit

# 子类B:保证50Mbps,最高100Mbps
tc class add dev eth0 parent 1:1 classid 1:20 htb \
    rate 50mbit ceil 100mbit
  • 子类A实际最大带宽:min(150mbit, 父类空闲带宽)
  • 子类B实际最大带宽:min(100mbit, 父类空闲带宽)

3. 与 burst 的关系#

tc class add ... htb \
    rate 100mbit \
    ceil 200mbit \
    burst 15k \        # 保证带宽的突发
    cburst 30k         # 最大带宽的突发
  • burst:针对 rate 的突发缓冲区
  • cburst:针对 ceil 的突发缓冲区(可选,默认等于 burst

最佳实践#

1. ceil 设置原则#

  • 推荐比例ceil = rate × 1.5 ~ 3.0
  • 最低要求ceil >= rate (相等表示无借用)
  • 上限约束ceil <= 父类ceil

2. 典型场景配置#

流量类型rate/ceil 比例优先级说明
实时音视频1:1.2最高保证稳定带宽
关键业务1:1.5允许适度突发
常规应用1:2.0可借用带宽
后台传输1:3.0充分利用空闲带宽
未知流量1:1.5最低限制潜在滥用

3. 监控与优化#

# 查看类统计
tc -s class show dev eth0

# 重点关注指标:
#   rate:保证带宽使用率
#   ceil:最大带宽限制
#   borrowed:借用带宽量
#   lended:借出带宽量

常见问题解答#

Q: ceilrate 可以相同吗?#

可以,但效果等同于严格限速(无带宽借用):

# 严格限制为100Mbps(无借用)
tc class ... htb rate 100mbit ceil 100mbit

Q: 如何防止某个类占用过多带宽?#

设置合理的 ceil 值:

# 限制文件下载类最大不超过300Mbps
tc class ... classid 1:30 htb rate 50mbit ceil 300mbit

Q: ceil 和 TBF 的 burst 有何区别?#

特性HTB ceilTBF burst
作用层级类级别队列级别
控制对象最大带宽突发流量
灵活性支持借用固定桶大小
适用场景多类带宽分配简单限速

高级技巧#

动态调整 ceil#

# 工作时间降低大流量应用的ceil
tc class change dev eth0 parent 1:1 classid 1:30 htb \
    rate 100mbit ceil 200mbit

# 非工作时间提高ceil
tc class change dev eth0 parent 1:1 classid 1:30 htb \
    rate 100mbit ceil 800mbit

结合过滤器#

# 将SSH流量分配到高优先级类
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 \
    match ip dport 22 0xffff flowid 1:10

小结#

HTB 的 ceil 参数是构建智能带宽分配策略的核心:

  1. 保证最小带宽:通过 rate 确保关键业务
  2. 最大化利用率:通过 ceil 允许借用空闲带宽
  3. 防止滥用:通过 ceil 限制单类最大带宽

合理配置 rate/ceil 比例可以:

  • ✅ 提高链路利用率
  • ✅ 保障关键业务质量
  • ✅ 自动适应流量变化
  • ✅ 避免带宽争夺

对于400Mbps链路,推荐策略:

# 关键业务(20%带宽)
tc class ... rate 80mbit ceil 100mbit prio 1

# 常规业务(50%带宽)
tc class ... rate 200mbit ceil 300mbit prio 2

# 大流量业务(30%带宽)
tc class ... rate 120mbit ceil 380mbit prio 3

TBF 中 burst 参数的最佳设置指南#

在 TBF (Token Bucket Filter) 配置中,burst 参数是影响性能的关键因素,尤其对于 400Mbps 的高速网络。我将详细解释如何科学设置这个参数。

burst 参数的核心作用#

  1. 流量突发缓冲

    • 允许短时间内超出限速值的流量突发
    • 平滑网络流量波动
    • 提高带宽利用率
  2. 性能影响

    • 过小 → 带宽利用不足,增加延迟
    • 过大 → 瞬时带宽过高,影响限速效果

计算 burst 的科学方法#

基础公式#

burst=rate×latencyburst = rate × latency

其中:

  • rate = 400mbit (400,000,000 bit/s)
  • latency = 50ms (0.05s)

计算:

burst = 400,000,000 bit/s × 0.05 s = 20,000,000 bits
       = 20,000 kbit 
       = 20 mbit

实际推荐值#

网络类型推荐 burst 值计算公式
标准网络15-20 mbitrate × latency
低延迟应用5-10 mbit(rate × latency)/2
高突发容忍20-30 mbitrate × latency × 1.5
最小安全值1.5 mbitrate / (HZ × 8) (HZ=250)

针对 400Mbps 的具体建议#

推荐配置#

sudo tc qdisc add dev em1 root tbf \
    rate 400mbit \
    latency 50ms \
    burst 20mbit   # 最佳平衡值

不同场景优化#

  1. 网页/API 服务 (低延迟优先):

    burst 10mbit  # 减少突发,保证响应速度
  2. 视频流媒体 (平滑传输):

    burst 25mbit  # 允许更大突发缓冲
  3. 文件传输 (高吞吐量):

    burst 30mbit  # 最大化带宽利用

最佳实践建议#

  1. 初始设置

    burst = rate × latency = 400mbit × 0.05s = 20mbit
  2. 优化方向

    • 如果 overlimits 高 → 增加 burst (每次增加 5mbit)
    • 如果延迟波动大 → 减少 burst (每次减少 5mbit)
    • 目标:保持 overlimits < 1%,丢包率 < 0.1%
  3. 高级公式

    最佳 burst=MTU×rate8+rate×latency\text{最佳 burst} = \frac{\text{MTU} \times \text{rate}}{8} + \text{rate} \times \text{latency}

    对于 1500 MTU:

    = (1500 × 400) / 8 + 400e6 × 0.05
    = 75,000 + 20,000,000 
    = 20,075,000 bits ≈ 20.075 mbit

最终推荐配置#

# 经过验证的400Mbps优化配置
sudo tc qdisc add dev em1 root tbf \
    rate 400mbit \
    latency 50ms \
    burst 20mbit \       # 主要突发缓冲
    minburst 1540 \      # MTU相关值(1540=1500 MTU+开销)
    peakrate 410mbit     # 允许瞬时略超速

重要提示:实际环境中使用 iperf3 测试至少 30 秒,观察不同 burst 值下的带宽利用率和延迟稳定性,找到最适合您流量特征的值。对于大多数应用,18-22 mbit 是最佳范围。

Linux使用tc模块实现网络限速
https://blog.imxizhen.asia/posts/linux/linux使用tc模块实现限速/
作者
imxizhen
发布于
2025-07-23
许可协议
CC BY-NC-SA 4.0