Linux下的流量控制(TC)和服务质量(QoS)

1 流量控制(Traffic Control)

最简单的流量控制往往是通过采集速率,在超过指定速率后丢弃数据包,但这种方案并不能将流量控制在指定速率,还会导致传输质量的较大损失。Linux内核内置了一个TC(流量控制)框架,主要实现流量限速、流量整形和策略应用(策略包括丢弃、NAT等)。在输出端口处建立一个队列,基于目的IP地址或目的子网的网络号,将需要延迟发送的数据包缓冲在队列中,并在合适的时间发送出去。因此,TC主要有三个要素:

  • Qdisc(Queue discipline)队列规定
  • filter 过滤器
  • class 类别

1.1 TC工作原理

TC原理
数据包在经过网卡后,按需求经过过滤器后被存入不同叶子队列中。

Linux在实现TC的时候,对队列进行了抽象,基本维护了两个回调函数指针,分别是入队(enqueue)操作和出队(dequeue)操作。对于叶子节点队列,进行数据包的入队和出队;对于非叶子节点的队列来说,并没有真正的数据包排入或排出,而是递归调用其它抽象队列的相应入队和出队操作。

1.2 TC的三个组成

1.2.1 Qdisc-无类队列和有类队列

无类队列(CLASSLESS QDISC):对进入网络设备(网卡)的数据流不加以区分,统一对待的队列规定。
有类队列(CLASSFUL QDISC):对进入网络设备(网卡)的数据包根据不同的需求,以分类的方式区别对待的队列规定。有类队列包括CBQ(Class Based Queueing,基于类别队列)、HTB(Hierarchy Token Bucket,分层令牌桶队列)和PRIO(优先级队列):

  • CBQ:实现了一个丰富的连接共享类别结构,既有限制带宽的能力,也具有带宽优先级别管理的能力。
  • HTB:实现了一个丰富的连接共享类别结构,可以很容易地保证每个类别的带宽,虽然它也允许特定的类可以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。
  • PRIO:很容易管理流量的优先级,但限制不能限制带宽,因为属于不同类别的数据包是顺序离队的。只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。

CBQ与HTB相比,HTB更佳。基于令牌桶算法能够在限制数据的平均传输速率的同时,还允许某种程度的突发传输。

令牌桶算法:
令牌桶算法

#include <iostream>
#include <atomic> 
#include <ctime>
#include <time.h>
 
class TokenBucket {
	typedef enum color{
		GREEN,
		RED
	}COLOR;
private :
	int m_cir; // 添加令牌的速率
	int m_cbs; // 桶的容量
 
	std::atomic<int64_t> m_clsLastUpdateTime; // 上次桶内令牌数更新时间
	std::atomic<int64_t> m_clsCurTokenNum; // 当前桶内令牌数
 
	// 毫秒级时间,不够用可以自己重写
	int64_t _get_cur_time() {
		return clock();
	}
 
public:
	TokenBucket(int cir, int cbs) {
		m_cir = cir;
		m_cbs = cbs;
		m_clsLastUpdateTime = _get_cur_time();
	}
 
	~TokenBucket() {}
 
	/************************ 
	  数据包处理函数
	  参数:token, 数据包大小
	  返回值:RED, 惩罚处理
		     GREED, 放行
	************************/
	COLOR packetProcess(int token) {
		int64_t nowTime;
		int64_t timeInterval;
		int64_t updateTokenNum;
		int64_t curTokenNum = m_clsCurTokenNum.load();
		if (token <= curTokenNum) {
			m_clsCurTokenNum.fetch_sub(token);
			return GREEN;
		}
		nowTime = _get_cur_time();
		timeInterval = nowTime - m_clsLastUpdateTime.load();
		updateTokenNum = timeInterval * m_cir + curTokenNum;
		if (updateTokenNum < token) {
			return RED;
		}
		else {
			updateTokenBucket(nowTime, updateTokenNum);
		}
		m_clsCurTokenNum.fetch_sub(token);
        return GREEN;
	}
 
	/************************ 
	  更新令牌桶内的时间以及数量
	  参数:time, 更新时间
		    num, 数量
	  返回值:void
	************************/
	void updateTokenBucket(int64_t time, int64_t num) {
		m_clsLastUpdateTime.store(time);
		m_clsCurTokenNum.store(num);
	}
};

代码来源:令牌桶算法原理及实现

1.2.2 过滤器

过滤器(filter)是用于对数据包进行分类的工具。

  1. u32过滤器:源/目的IP地址,源/目的端口,协议类型,服务类型(TOS)
sudo tc filter add dev ens33 parent 1:0 protocol ip prio 1 u32 match ip src 192.168.79.131 flowid 1:1 #源IP地址
sudo tc filter add dev ens33 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.79.131 flowid 1:1 #目的地址
sudo tc filter add dev ens33 parent 1:0 protocol ip prio 1 u32 match ip sport 80 0xffff flowid 1:1 #源端口
sudo tc filter add dev ens33 parent 1:0 protocol ip prio 1 u32 match ip dport 80 0xffff flowid 1:1 #目的端口
sudo tc filter add dev ens33 parent 1:0 protocol ip prio 1 u32 match ip protocol 1 0xffff flowid 1:1 #根据/etc/protocols来决定协议号
sudo tc filter add dev ens33 parent 1:0 protocol ip prio 1 u32 match ip tos 0x10 0xff flowid 1:1 #选择交互和最小延迟的数据流,匹配大量传输
  1. 根据iptables的标记fwmark进行过滤
sudo iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6
sudo tc filter add dev ens33 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1
  1. 根据路由,具体可见下一节中的操作实例。

1.2.3 类别

类(class)组成一个树,每个类都只有一个父类,而一个类可以有多个子类。

1.3 基本命令

1.3.1 TBF操作实例

sudo tc qdisc add dev ens33 handle 1: root tbf rate 100Mbit burst 100Kbit limit 200Mbit

Size: 168.9M Time: 14.19s Speed: 11.35MB/s

1.3.2 CBQ操作实例

虚拟机IP地址
18.04(Server)192.168.79.131
16.04192.168.79.129
16.04_1192.168.79.132
  1. 针对网络物理设备(网卡ens33)绑定队列,针对一个网卡只需要建立一个队列:
tc qdisc add dev ens33 root handle 1: cbq bandwidth 10Mbit avpkt 1000 cell 8 mpu 64

将一个cbq队列绑定到网络物理设备ens33上,其编号为1:0;网络物理设备eth0的实际带宽为10Mbit,包的平均大小为1000字节;包间隔发送单元的大小为8字节,最小传输包大小为64字节。

  1. 针对一个队列需建立一个根分类,对于分类,按其分类的编号顺序起作用,编号小的优先;一但符合某个分类匹配规则,通过该分类发送数据包,则其后的分类不在起作用:
tc class add dev ens33 parent 1:0 classid 1:1 cbq bandidth 10Mbit rate 10Mbit maxburst 20 allot 1514 prio 8 avpkt 1000 cell 8 weight 1Mbit 

该队列的最大可用带宽为10Mbit,实际分配的带宽为10Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为8,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相当于实际带宽的加权速率为1Mbit。

  1. 在根分类里建立子分类1:2:
tc class add dev ens33 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 8Mbit maxburst 20 allot 1514 prio 2 avpkt 1000 cell 8 split 1:0 bounded 

该队列的最大可用带宽为10Mbit,实际分配的带宽为8Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为2,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相当于实际带宽的加权速率为800Kbit,分类的分离点为1:0,且不可借用未使用带宽。

在根分类里建立子分类1:3:

tc class add dev ens33 parent 1:1 classid 1:3 cbq bandwidth 10Mbit rate 2Mbit maxburst 20 allot 1514 prio 1 avpkt 1000 cell 8 split 1:0

该队列的最大可用带宽为10Mbit,实际分配的带宽为2Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为1,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相当于实际带宽的加权速率为200Kbit,分类的分离点为1:0。

  1. 为每一次分类建立一个过滤器,并为每一个分类建立一个路由映射:
tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 2 flowid 1:2
tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 3 flowid 1:3
  1. 与过滤器相配合,建立特定的路由表:
ip route add 192.168.79.129 dev eth0 via 192.168.79.131 realm 2

发往主机192.168.79.129的数据包通过分类2转发(分类2的速率8Mbit)。

ip route add 192.168.79.132 dev eth0 via 192.168.79.131 realm 3

发往主机192.168.79.132的数据包通过分类3转发(分类3的速率1Mbit)。

  1. 通过由两个FTP客户机分别从服务器下载同一个168.9M的文件,通过改变参数得到以下限速结果:
SituationNameTimeSpeed
未设置TC16.040.86s187MB/s
未设置TC16.04_10.61s263MB/s
8Mbit bounded16.04164s1004KB/s
5Mbit bounded16.04270s610KB/s
8Mbit16.040.98s164MB/s
2Mbit16.04_11.14s141MB/s

8Mbit = 8192Kbit/s = 1024 KB/s
5Mbit = 640KB/s

1.3.3 HTB操作实例

步骤大致如上一节,不赘述。

sudo tc qdisc add dev ens33 root handle 1: htb
sudo tc class add dev ens33 parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit
sudo tc class add dev ens33 parent 1:1 classid 1:2 htb rate 8Mbit ceil 8Mbit
sudo tc class add dev ens33 parent 1:1 classid 1:2 htb rate 2Mbit ceil 10Mbit
sudo tc filter add dev ens33 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.79.129 flowid 1:2
sudo tc filter add dev ens33 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.79.132 flowid 1:3

同样由两个FTP客户机分别从服务器下载同一个168.9M的文件,通过改变参数得到以下限速结果:

SituationNameTimeSpeed
未设置TC16.040.86s187MB/s
未设置TC16.04_10.61s263MB/s
rate 8 ceil 816.04176s933KB/s
rate 2 ceil 1016.04_1141s1.14MB/s
rate 2 ceil 216.04_1706s233KB/s

2Mbit = 256KB/s
10Mbit = 1.25MB/s

1.3.4 监视

主要包括对队列、分类、过滤器和路由状况进行监视。
对队列、分类和过滤器的监视:

tc (-s) qdisc/class/filter ls dev eth0

对路由情况的监视:

ip route

1.3.5 维护

主要包括对队列、分类、过滤器和路由的增添、修改和删除。

增添动作一般依照 队列 -> 分类 -> 过滤器 -> 路由 的顺序进行;修改动作则没有什么要求;删除则依照路由 -> 过滤器 -> 分类 -> 队列 的顺序进行。

2 服务质量(Quality of Service)

2.1 概念

QoS现指解决网络延迟和阻塞等问题的一种技术,用于区分流量,保证高优先级带宽的要求与网络质量。QoS技术本身不会增加网络带宽,而是在有限的带宽资源下,如何平衡地为各种业务分配带宽,针对不同需求,为业务提供端到端的服务质量保证。实现QoS的一个最基本的方法就是分类和标记。
一个QoS策略包含一个或多个限速规则,一个限速规则包含一个或多个流分类规则。QoS通过流分类划分流量,并根据配置的限速规则的优先级保证高优先级限速下的带宽。
影响网络服务质量的因素,也就成为QoS的度量指标,包括带宽、时延和抖动。

2.2 服务模型

2.2.1 Best-Effort服务模型

Best-Effort是最简单也是最早出现的QoS服务模型。在这种模型中,网络中的设备上除了保证网络之间路由可达之外,不需要部署额外的功能。应用程序可以在任何时候发出任意数量的报文,而且不需要通知网络。网络只是尽最大的可能性来发送报文,但对时延、可靠性等性能不提供任何保证。
在理想状态下,如果有足够的带宽,Best-Effort是最简单的服务模式。而实际上,这种“简单“带来一定的限制。因此,Best-Effort适用于对时延、可靠性等性能要求不高的业务,如FTP、E-Mail等。

2.2.2 IntServ服务模型

InterServ模型下,网络需要为某个业务预留一条专用通道。这种资源预留的状态称为“软状态”。为了保证这条通道不被占用,RSVP会定期发送大量协议报文进行探测。通过RSVP,各网元可以判断是否有足够的资源可以预留。只有所有的网元都预留了足够的资源,专用通道方可建立。

2.2.3 Differ服务模型

DiffServ服务模型,也叫差分服务模型,意思就是提供有差别的服务。DiffServ模型中,网络中的流量可以根据多种条件被分成多个类,或者标记不同的优先级。当网络出现拥塞时,不同的类会享受不同的优先处理,从而实现差分服务。同一类的业务在网络中会被聚合起来统一发送,保证相同的延迟、抖动、丢包率等QoS指标。
报文分类是基础,是有区别地实施服务的前提,流量监管、流量整形和接口限速主要用于预防拥塞,拥塞管理和拥塞避免是用来解决拥塞。

2.3 技术背景

QoS Workflow:
当数据包进入设备后,它依次经过标记、计量、管制、重分类、队列、整形以及优先级调度。

分类:将数据分为不同类别,不会修改原来的数据包;
标记:将数据设置为不同的优先级,会修改原来的数据包;
计量:通过漏桶算法或令牌桶算法实现,计量后的数据包会根据不同的整形类别分别保存在缓冲区中,待满足对应的要求后再发送;
管制:丢弃超出带宽的数据包;
整形:将超出带宽的数据包缓存在内存中,限制流出某一网络的某一连接的流量与突发,使这类报文以比较均匀的速度向外发送;
队列:当网络发生拥塞后,数据还是要被传递的,依照什么样的方式来传数据,就需要队列的指导。

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值