众所周知,在互联网诞生之初都是各个高校和科研机构相互通讯,并没有网络流量控制方面的考虑和设计,IP协议的原则是尽可能好地为所有数据流服务,不同的数据流之间是平等的。
然而多年的实践表明,这种原则并不是最理想的,有些数据流应该得到特别的照顾, 比如,远程登录的交互数据流应该比数据下载有更高的优先级。
因此细粒度的对操作系统资源的控制是我们每一个人都想做的事,自己的地盘自己做主。
本文主要从网络资源来对linux系统中的资源进行调度和分配
限制网络资源背景Linux操作系统中,报文分组从输入网卡(入口)接收进来,经过路由的查找, 以确定是发给本机的,还是需要转发的。如果是发给本机的,就直接向上递交给上层的协议,比如TCP,如果是转发的, 则会从输出网卡(出口)发出。网络流量的控制通常发生在输出网卡处。虽然在路由器的入口处也可以进行流量控制,Linux也具有相关的功能, 但一般说来, 由于我们无法控制自己网络之外的设备, 入口处的流量控制相对较难。本文将集中介绍出口处的流量控制。
相关概念流量控制(Traffic Control, tc)是Linux内核提供的流量限速、整形和策略控制机制。它以qdisc-class-filter的树形结构来实现对流量的分层控制
在Linux中,流量控制都是通过TC这个工具来完成的。通常, 要对网卡进行流量控制的配置,需要进行如下的步骤:
- 为网卡配置一个队列;
- 在该队列上建立分类;
- 根据需要建立子队列和子分类;
- 为每个分类建立过滤器。
从上图中可以看到,tc由qdisc、fitler和class三部分组成:
- qdisc通过队列将数据包缓存起来,用来控制网络收发的速度
- 常见的classless qdisc有:choke, codel, p/bfifo,fq, fq_codel, gred, hhf, ingress,mqprio, multiq, netem, pfifo_fast, pie, red, rr, sfb, sfq, tbf。linux默认使用的就是fifo_fast。
- 常见的classful qdisc有:ATM, CBQ, DRR, DSMARK, HFSC, htb, PRIO, QFQ
- class用来表示控制策略
- 分类只存在于可分类排队规则(classful qdisc)(例如,HTB和CBQ)中。
- default 这是HTB排队规则的一个可选参数,默认值为0, 当值为0时意味着会绕过所有和rootqdisc相关联的分类,然后以最大的速度出队任何未分类的流量。
rate 这个参数用来设置流量发送的最小期望速率。这个速率可以被当作承诺信息速率(CIR), 或者给某个叶子分类的保证带宽。
ceil 这个参数用来设置流量发送的最大期望速率。租借机制将会决定这个参数的实际用处。 这个速率可以被称作“突发速率”。
burst 这个参数是rate桶的大小(参见令牌桶这一节)。HTB将会在更多令牌到达之前将burst个字节的数据包出队。
cburst 这个参数是ceil桶的大小(参见令牌桶这一节)。HTB将会更多令牌(ctoken)到达之前将cburst个字节的数据包出队。
quantum 这个是HTB控制租借机制的关键参数。正常情况下,HTB自己会计算合适的quantum值,而不是由用户来设定。对这个值的轻微调整都会对租借和整形造成巨大的影响,因为HTB不仅会根据这个值向各个子分类分发流量(速率应高于rate,小于ceil),还会根据此值输出各个子分类中的数据。
r2q 通常,quantum 的值由HTB自己计算,用户可以通过此参数设置一个值来帮助HTB为某个分类计算一个最优的quantum值。
- filter用来将数据包划分到具体的控制策略中
- 包含了一个分类器实现,常见的分类器如u32,u32分类器可以允许用户基于数据包的属性来选择数据包。
语法不再赘述,相关参考资料里有。
入流量调度Linux中的QoS分为入口(Ingress)部分和出口(Egress)部分,入口部分主要用于进行入口流量限速(policing),出口部分主要用于队列调度(queuing scheduling)。
大多数排队规则(qdisc)都是用于输出方向的,输入方向只有一个排队规则,即ingress qdisc。ingress qdisc本身的功能很有限,但可用于重定向incoming packets。通过Ingress qdisc把输入方向的数据包重定向到虚拟设备ifb,而ifb的输出方向可以配置多种qdisc,就可以达到对输入方向的流量做队列调度的目的。
IFB说明:
一个例子IFB — Intermediate Functional Block device。 Q: How can we use qdisc (e.g., netem) on incoming traffic? A: You need to use IFB. This network device allows attaching queueing disciplines to incoming packets. To use an IFB, you must have IFB support in your kernel (configuration option CONFIG_IFB). Assuming that you have a modular kernel, the name of the IFB module is ifb and may be loaded using the command modprobe ifb (if you have modprobe installed) or insmod /path/to/module/ifb.
ip link set ifb0 up
ip link set ifb1 up
By default, two IFB devices(ifb0 and ifb1) are created. IFB allows for queueing incoming traffic for shaping instead of dropping.
参考资料:输入方向的流量控制 --ifb_eydwyz的专栏-CSDN博客
#!/bin/bash
#fb驱动并创建ifb网卡(使用ifconfig -a 如果看到已有则无需该步骤)
#分别为出设备和入设备
outdevice=ens33
indevice=ifb0
modprobe ifb numifbs=1
# up网卡
ip link set dev $indevice up
# ------
# 清除原有的根队列(根据实际情况操作,非必要)
tc qdisc del dev $outdevice root 2>/dev/null
tc qdisc del dev $outdevice ingress 2>/dev/null
tc qdisc del dev $indevice root 2>/dev/null
# 将$outdevice的ingress流量全部重定向到 $indevice 处理
tc qdisc add dev $outdevice handle ffff: ingress
tc filter add dev $outdevice parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $indevice
# $outdevice的出向限速:$outdevice添加根队列,使用htb,添加1:1类,使用htb
tc qdisc add dev $outdevice root handle 1: htb r2q 625 default 65
tc class add dev $outdevice parent 1: classid 1:1 htb rate 1000Mbit
# $outdevice的入向限速:$indevice添加根队列,使用htb,添加1:1类,使用htb
tc qdisc add dev $indevice root handle 1: htb r2q 625 default 65
tc class add dev $indevice parent 1: classid 1:1 htb rate 1000Mbit
# $outdevice的出向限速:$outdevice设备添加子类\对应的filter配置规则和子类的队列
tc class add dev $outdevice parent 1:1 classid 1:10 htb rate 10Mbit
tc filter add dev $outdevice parent 1: protocol all prio 1 u32 match ip dst 192.168.0.2 classid 1:10
tc qdisc add dev $outdevice parent 1:10 handle 10: sfq
# $outdevice的出向限速:$outdevice设备添加子类\对应的filter配置规则和子类的队列
tc class add dev $outdevice parent 1:1 classid 1:11 htb rate 20Mbit
tc filter add dev $outdevice parent 1: protocol all prio 1 u32 match ip dst 192.168.0.3 classid 1:11
tc qdisc add dev $outdevice parent 1:11 handle 11: sfq
# $outdevice的入向限速:$indevice设备添加子类\对应的filter配置规则和子类的队列
tc class add dev $indevice parent 1:1 classid 1:10 htb rate 10Mbit
tc filter add dev $indevice parent 1: protocol all prio 1 u32 match ip src 192.168.0.2 classid 1:10
tc qdisc add dev $indevice parent 1:10 handle 10: sfq
# $outdevice的入向限速:$indevice设备添加子类\对应的filter配置规则和子类的队列
tc class add dev $indevice parent 1:1 classid 1:11 htb rate 20Mbit
tc filter add dev $indevice parent 1: protocol all prio 1 u32 match ip src 192.168.0.3 classid 1:11
tc qdisc add dev $indevice parent 1:11 handle 11: sfq
网络压力测试
压力测试工具使用iperf网络测试工具
常用参数指南(详见附录):
-c/s:客户端模式/服务端模式
-p:指定iperf测试端口
-i:指定报告间隔
-b:设置UDP的发送带宽,单位bit/s
-t:设置测试的时长,单位为秒,不设置默认10s
-l:指定包大小,TCP默认8k,UDP默认1470字节
# 针对TCP进行带宽性能测试
#服务端命令:
iperf -s -i 1 -p 3389
#
iperf -c 192.168.158.128 -p 3389 -i 1
#针对UDP进行带宽性能测试
#服务端命令
iperf -u -s -i 1 -p 3389
#客户端命令
iperf -u -c 192.168.158.128 -p 3389 -b 1500M -i 1
# 参考资料:iperf网络测试工具, https://cloud.tencent.com/developer/article/1688469
带宽查看使用工具iftop
TX:发送流量 RX:接收流量 TOTAL:总流量 Cumm:运行iftop到目前时间的总流量 peak:流量峰值 rates:分别表示过去 2s 10s 40s 的平均流量
执行脚本前后,对于网络带宽进行检测,发现流量带宽明显受到TC的控制。实验成功。
参考资料:流量控制 https://tonydeng.github.io/sdn-handbook/linux/tc.html
Traffic Control HOWTO https://tldp.org/HOWTO/Traffic-Control-HOWTO/
Linux TC(Traffic Control)框架原理解析, https://blog.csdn.net/dog250/article/details/40483627
linux下使用tc(Traffic Control) 流量控制命令模拟网络延迟和丢包
TC流量控制 https://blog.csdn.net/who538592/article/details/79483323