tc带宽限制

概述

tc是 Linux 内核提供的流量控制、带宽管理、流量分类和流量整形工具。它通过各种队列规则(qdiscs)、分类器(classes)和过滤器(filters)来实现这些功能。

流量控制的基本概念

qdisc(队列规则):决定了数据包如何在网络接口的发送队列中排队和调度。常见的队列规则有:

  • pfifo_fast:默认的无流量控制的队列规则。
  • htb:用于精细的带宽管理和流量整形。
  • tbf:简单的速率限制器。

class(分类器):qdisc 可以包含多个 class,每个 class 可以拥有自己的 qdisc(队列规则),从而实现更复杂的流量管理。

filter(过滤器):用于匹配特定的流量并将其分配到相应的 class(分类器)。常用的过滤器类型有 u32、tcindex、route 等。


综上,qdisc用于制定流量管理规则;class用于分类规则;filter用于流量路由,决定流量由哪个分类处理。

配置流程

tc流量控制命令执行后,会立即生效;如下是配置步骤:

1.0> 创建根队列规则

必须先添加根队列规则(qdisc),根队列规则是所有流量控制的基础,没有根队列规则,就无法创建分类器(class)和过滤器(filter),如下是创建根队列规则

sudo tc qdisc add dev eth0 root handle 1: htb default 30
## dev eth0:指定网络接口。
## root:表示这是一个根队列规则。
## handle 1::给此根队列规则分配一个唯一标识(句柄),以便后续对其进行引用
## htb:指定使用htb算法,即速率限制器
## default 30:没有匹配到特定分类器的流量将被分配到 classid 为 1:30 的分类器;1:30是指handle为1的规则队列下的classid为30的分类。

2.0> 创建主分类器

通常情况下,会在跟队列规则下先创建一个主分类器,然后再在主分类器下创建无数个子分类器;这样的层级设定使流量管理有更高的扩展性、灵活性、可读性,但也更复杂;如果你的流量控制规则比较简单,仅仅只是控制带宽和优先级,则不必创建主分类器。

3.0> 创建子分类器

sudo tc class add dev eth0 parent 1: classid 1:10 htb rate 10mbit ceil 100mbit prio 1 burst 12K
## dev eth0:指定该类应用于哪个网络接口,这里是 eth0 接口。
## parent 1::指定该类的父类或父队列;1:表示这是属于标识符为1的根队列(qdisc)。
## classid 1:10:这个分类器的ID,1为级队列规则的handle标识,10为当前分类器的id, 1:10共同唯一的确定一个分类器;
## htb:使用 htb 调度算法;htb用于带宽管理,允许定义速率限制和优先级。
## rate 10mbit:限制带宽为10Mbps,即至少可以确保有10Mbps带宽;
## ceil 100mbit:允许的最大带宽为100Mbps,即如果有多余带宽,该类最多可以使用100 Mbit/s的带宽;
## prio 1:优先级设置为 1(数值越小,优先级越高),在带宽竞争时,高优先级类会优先获得带宽。
## burst 12K:突发大小,允许一定量的数据以高于配置的平均速率发送,这非常重要,不设置会影响网络的质量和稳定性;通常设置带宽的10%。

4.0> 添加过滤器

过滤器用于流量路由,将不同端口的流量分配到不同分类器

sudo tc filter add dev eth0 protocol all parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10
## dev eth0: 指定规则应用到的网络接口,这里是 eth0。
## protocol all: 指定过滤器匹配的网络协议,这里匹配了所有协议,包括 IPv4、IPv6 以及其他可能的协议
## parent 1:0: 指定过滤器的父类,即过滤器所属的队列规则,此处 1:0 表示根队列规则。
## prio 1: 指定过滤器的优先级,数值越小,优先级越高;当有多个过滤器规则匹配同一个数据包时,优先级高的过滤器先处理,即处理顺序;
## u32: 使用 u32 过滤器匹配规则;u32是一种高级匹配规则,用于对数据包的各个字段进行灵活的匹配;包括数据包的源地址、目标地址、源端口、目标端口、协议等,并根据匹配结果执行相应的操作。
## match ip dport 22 0xffff: 指定匹配规则,此处匹配端口为22的数据包;dport是欲匹配的端口号,0xffff是一个掩码,指示要匹配的端口范围,0xffff表示从所有端口中匹配指定端口。dport设置指定端口的出站流量,还有别外一个取值sport,用于限制入站端口的流量。
## flowid 1:10: 指定匹配到的流量应该被发送到的分类器,这里是发送到 1:10 的分类器;

综上,流量包进入系统后,会先经过根队列规则,再根据过滤器规则的匹配情况,确定流量包应该被发送到哪个子分类器;最后,流量包会经过相应的子分类器进行处理,根据子分类器的规则进行分配或限制带宽;最终到业务应用层。

最佳实践

在对大量端口进行流量管理时,单纯使用tc是一种性能较低的方式;例如,管理1万个端口的带宽时,使用tc有两种管理方式:一是建立1万个过滤器,二是给每个过滤器设置端口范围;但这有以下弊端:

a. 过滤器会占用内存,数量过多的过滤器会占用大量内存,因此不推荐这样做;

b. 频繁添加、删除过滤器,会消耗CPU性能,因此推荐提前配置好特定端口范围,不要在程序运行过程中频繁操作流量管理;

c. 可以给过滤器指定目标端口范围,以此可极大降低过滤器的数量,但过滤器匹配大范围的端口时会变得非常复杂和低效,因此不推荐使用。

综上,推荐使用iptables和TC结合的方法来管理大量端口的流量,并且是提前配置好,不要在程序运行过程中配置;具体做法是使用iptables来标记流量,然后在tc中根据标记的流量应用带宽限制,这种方法可以有效地管理大量端口。

d. 不论是tc或iptables,过于复杂的规则都会消耗系统性能。

1.0> 使用 iptables 标记流量

## 标记端口范围为1000~2000的所有流量
sudo iptables -t mangle -A PREROUTING -p tcp -m multiport --dports 1000:2000 -j MARK --set-mark 1
sudo iptables -t mangle -A PREROUTING -p udp -m multiport --dports 1000:2000 -j MARK --set-mark 1
sudo iptables -t mangle -A PREROUTING -p udplite -m multiport --dports 1000:2000 -j MARK --set-mark 1
sudo iptables -t mangle -A PREROUTING -p sctp -m multiport --dports 1000:2000 -j MARK --set-mark 1
sudo iptables -t mangle -A PREROUTING -p dccp -m multiport --dports 1000:2000 -j MARK --set-mark 1
## -p 指定协议,可以是tcp、udp等,不支持直接指定所有协议,每一个标记只能定义一种协议;上述命令是将1000~2000端口的tcp、udp等协议都标记为1;
## -t mangle:使用mangle表进行数据包修改,mangle表用于修改数据包的服务类型或标记(Mark);
## -A PREROUTING:-A表示添加(Append)一条规则,PREROUTING链表示处理数据包在路由决策之前,即所有数据包在被路由之前会首先经过这条链。
## -m multiport --dports 1000:2000: 匹配目标端口范围为 1000 到 2000 的所有数据包,不限制协议(UDP或TCP)。
## -j MARK --set-mark 1:将匹配的数据包标记为1

2.0> 使用 tc 进行带宽管理 - 添加过滤器规则

iptables和tc结合时,tc的根规则队列和分类器配置保存原样,仅需调整tc过滤器的配置,如下:

## 根据 iptables 标记的流量应用过滤器
sudo tc filter add dev eth0 protocol all parent 1:0 prio 1 handle 1 fw flowid 1:1
## handle 1 fw:1是标识符的具体值,表示这个过滤器将匹配标记为1的数据包,fw 表示这个标记是由 iptables 防火墙规则设置的;
## flowid 1:1:指定匹配到的流量应该被引导到的分类器,1:1 表示将流量引导到句柄为 1:1 的分类器,通常这个分类器定义了具体的带宽和优先级限制规则。
## 其他参数配置,详见上文。

3.0> 持久化配置

为了确保在重启后规则依然生效,要将iptables和tc的流量管理命令写入脚本并在系统启动时执行,或者使用 /etc/network/if-up.d/ 脚本来执行。在 Ubuntu 和基于 Debian 的系统中,/etc/network/if-up.d/ 目录包含一组脚本,这些脚本在网络接口(例如 eth0)启动并成功配置后自动运行。这是一个管理网络接口的标准机制,使管理员能够在接口上线时自动执行特定的配置或任务。/etc/network/if-up.d/ 目录的作用如下:

a. 执行条件:目录中的脚本在网络接口成功启动并配置后执行。这通常包括 DHCP 分配 IP 地址,静态 IP 地址配置等情况。

b. 自动化:允许管理员在网络接口启动时自动执行特定的配置任务,如设置防火墙规则、启动服务、应用 QoS 规则等。

分类器的带宽优先级

在 TC 中的 HTB 调度器里,`prio` 表示类的优先级。优先级决定了在带宽竞争时,哪个类会优先获得带宽。

1.0> HTB的优先级(prio)

`prio`值越小,优先级越高:在 HTB 中,`prio` 值越小,表示这个类的优先级越高。当多个类同时请求带宽时,优先级高的类会首先获得带宽分配。

带宽竞争时的处理:如果高优先级的类有未满足的带宽需求,它会在低优先级的类之前得到带宽。只有在高优先级类的带宽需求被满足之后,低优先级的类才能得到带宽。

2.0> 优先级的作用

确保关键流量:优先级允许你确保关键流量在网络拥塞时得到优先处理。例如,实时视频流、VoIP、SSH 等需要低延迟和稳定带宽的流量可以被设置为高优先级。

带宽分配策略:通过设置不同的优先级,可以细粒度地控制不同类型流量的带宽分配策略,确保重要流量不受干扰。在带宽充足的情况下,各个优先级的类都可以获得其最高带宽,但在带宽不足时,会首先满足高优先级类的带宽需求,剩余的带宽才会分配低给优先级的类。

3.0> 重要性

网络稳定性:通过正确设置优先级,可以确保重要流量的稳定性和可靠性,特别是在网络资源有限的情况下。

QoS(服务质量)管理:优先级是实现 QoS 的重要手段,可以确保不同类型的流量根据其重要性和需求得到相应的服务质量保障。

实践

为了避免冲突、确定兼容性,使用 10000~65000 之间的端口是比较推荐的范围;具体操作如下:

1. 将10000~20000定义为付费端口,20001~65000定义为免费端口。

2. 在云服务器防火墙处,仅放行 10000~65000 端口。

3. 付费端口的流量优先级为1,免费端口的流量优先级2;其它所有未定义的端口,优先及为1。

4. 操作:

## 1.0> 获取默认网络接口(网卡),如下命令可以返回多个相同的网卡
ip route | grep default | awk '{print $5}'

## 2.0> 创建tc根队列规则
sudo tc qdisc add dev ens33 root handle 1: htb default 30

## 2.1> 创建40个tc子分类器,分别对应优先级为1和2的1~20Mbps带宽

## 2.2> 创建1个子分类器,作为默认分类器


## 2.3> 创建tc过滤器
sudo tc filter add dev ens33 protocol ip parent 1:0 prio 1 handle 1 fw flowid 1:1

sudo tc filter add dev eth0 parent 1: protocol ip prio 1 handle 10 fw flowid 1:10

iptables -t mangle -A PREROUTING -p tcp -m multiport --dports 1000:2000 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m multiport --sports 8000:9000 -j MARK --set-mark 10


我想通过iptables和tc结合的方式来限制指定端口的带宽和流量

端口规划方案:

1个Frps服务占5个端口,在云服务器防火墙处放开 10000~60001 端口,其它常用端口按需放开,必须按需要放开,因此其它端口的流量优先级较高。

分析结果:

付费端口范围为10000~20000,共10000个端口,可以承载2000个连接,当连接占满时将完全覆盖服务器成本,并且可能数倍于成本。

10000个端口平均分为10种带宽大小,即建立10个iptables标记,标记号对应带宽,分别为:1、2、3、4、5、6、8、10、15、20

带宽分类为:1、2、3、4、5、6、8、10、15、20Mbps


付费端口范围为20001~60001,共40000个端口,可以承载8000个连接,免费连接不可能完全占满服务器。

40000个端口平均分为5种带宽大小,即建立5个iptables标记,标记号对应带宽,分别为:100、200、300、400、500、600、800、1000、1500、2000

带宽分类为:1、2、3、4、5Mbps,免费连接不能超过5Mbps,否则可能会分流其它地区的付费用户。


综上,建立15个iptables标记,10个付费标记,5个免费标记;对应的建立15个过滤器、15个子分类器。

业务之外,再创建一个子分类器,作为默认的分类器来处理其它所有流量。


测量验证:

付费端口测试:对1Mbps和4Mbps端口进行测试,对应端口为10000和130000

免费端口测试:对1Mbps和4Mbps端口进行测试,对应端口为20000和44000


流量优先级测试:对免费4Mbps端口和付费20Mbsp端口进行测试,先开始免费端口测试,再开始付费端口测试,以确认流量优先级的有效性。


通过iptables和tc做流量管理时,如何判断流量是否经过过滤器和分类器?


最终实践

注意:不要使用iptables,实际操作中iptables非常难控制,经常不生效;因此不推荐使用,仅使用tc能极大降低项目的复杂度

sudo tc qdisc del dev eth0 root && iptables -t mangle -F && iptables -t mangle -X

## 添加根队列规则
sudo tc qdisc add dev eth0 root handle 1: htb default 30

## 添加默认分类器
## burst统一设置为带宽的10%,并且要设置为整数
sudo tc class add dev eth0 parent 1: classid 1:30 htb rate 2mbit ceil 2mbit prio 1 burst 12K

## 添加其它分类器
## burst统一设置为带宽的10%,并且要设置为整数
sudo tc class add dev eth0 parent 1: classid 1:11 htb rate 2mbit ceil 2mbit prio 1 burst 12K


举报

© 著作权归作者所有


0