##使用过程中查了很多资料,特整理如下,方便随时查看##
##介绍##
报文分组从输入网卡(入口)接收进来,经过路由的查找,以确定是发给本机的,还是需要转发的。如果是发给本机的,就直接向上递交给上层的协议,比如TCP,如果是转发的,则会从输出网卡(出口)发出。网络流量的控制通常发生在输出网卡处,Linux内核中由TC(Traffic Control)实现。TC是利用队列规定建立处理数据包的队列,并定义队列中的数据包被发送的方式,从而实现流量控制。基本原理:
接收包从输入接口(Input Interface)进来后,经过流量限制(Ingress Policing)丢弃不符合规定的数据包,由输入多路分配器(Input De-Multiplexing)进行判断选择。如果接收包的目的地是本主机,那么将该包送给上层处理,否则需要进行转发,将接收包交到转发块(Forwarding Block)处理。转发块同时也接收本主机上层(TCP、UDP等)产生的包。转发块通过查看路由表,决定所处理包的下一跳。然后,对包进行排列以便将它们传送到输出接口(Output Interface)。一般我们只能限制网卡发送的数据包,不能限制网卡接收的数据包,所以我们可以通过改变发送次序来控制传输速率。
##流量控制对象:QDISC(排队规则) CLASS(类别) FILTER(过滤器)##
流量控制的一个基本概念是队列(Qdisc),每个网卡都与一个队列(Qdisc)相联系。每当内核需要将报文分组从网卡发送出去,都会首先将该报文分组添加到该网卡所配置的队列中,由该队列决定报文分组的发送顺序。因此可以说,所有的流量控制都发生在队列中。有些队列的功能是非常简单的,它们对报文分组实行先来先走的策略。有些队列则功能复杂,会将不同的报文分组进行排队、分类,并根据不同的原则,以不同的顺序发送队列中的报文分组。为实现这样的功能,这些复杂的队列需要使用不同的过滤器(Filter)来把报文分组分成不同的类别(Class)。这里把这些复杂的队列称为可分类(Classiful)的队列。通常,要实现功能强大的流量控制,可分类的队列是必不可少的。因此,类别(Class)和过滤器(Filter)也是流量控制的另外两个重要的基本概念。类别(Class)和过滤器(Filter)是队列的内部结构,并且可分类的队列可以包含多个类别,同时,一个类别又可以进一步包含有子队列,或者子类别。所有进入该类别的报文分组可以依据不同的原则放入不同的子队列 或子类别中,以此类推。而过滤器(Filter)是队列用来对数据报文进行分类的工具,它决定一个数据报文将被分配到哪个类别中。
在Linux中,可以配置很多类型的队列,比如CBQ、HTB等,其中CBQ 比较复杂,不容易理解。HTB(Hierarchical Token Bucket)是一个可分类的队列, 与其他复杂的队列类型相比,HTB具有功能强大、配置简单及容易上手等优点。
在TC中,使用"major:minor"这样的句柄来标识队列和类别,其中major和minor都是数字。对于队列来说,minor总是为0,即"major:0"这样的形式,也可以简写为"major: "。比如,队列1:0可以简写为1:。需要注意的是,major在一个网卡的所有队列中必须是惟一的。对于类别来说,其major必须和它的父类别或父队列的major相同,而minor在一个队列内部则必须是惟一的(因为类别肯定是包含在某个队列中的)。举个例子,如果队列2:包含两个类别,则这两个类别的句柄必须是2:x这样的形式,并且它们的x不能相同,比如2:1和2:2。
##使用基本步骤##
Linux流量控制主要分为建立队列、建立分类和建立过滤器三个方面。
1) 针对网络物理设备(如以太网卡eth0)绑定一个队列qdisc;
2) 在该队列上建立分类class;
3) 为每一分类建立一个基于路由的过滤器filter;
4) 最后与过滤器相配合,建立特定的路由表。
##相关单位##
tc命令所有的参数都可以使用浮点数,可能会涉及到以下计数单位。
带宽或流速单位:
kbps 千字节/s mbps 兆字节/s (bps或者一个无单位数字,表示字节数/s)
kbit KBits/s mbit MBits/s
数据的数量单位
kb或k 千字节 mb或m 兆字节 (b或者一个无单位数字,字节)
kbit 千bit mbit 兆bit
时间的计量单位
s, sec或secs 秒 ms, msec或mescs 毫秒
us, use, usecs或一个无单位数字 微s
##举例##
『创建根队列--》创建类别class--》为类别创建对应过滤器,对应网卡接收的数据包会一层一层下发到过滤器进行过滤或相关处理』
1)为网卡创建根队列或htb队列或cbq队列
有关队列的TC命令的一般形式为:
# tc qdisc [add | change | replace | link] dev DEV [parent qdisk-id |root] [handle qdisc-id] qdisc [qdisc specific parameters]
==》sar -n DEV 1 2 命令查看当前机器所使用的以太网卡是哪个
==》tc qdisc add dev eth1 root handle 1: prio
为网卡eth1建议一个队列,名字为root,句柄为1
==》tc qdisc add dev eth1 root handle 1:htb default 11
为网卡eth1添加root根队列,"handle 1:"表示队列的句柄为1: ,"htb"表示要添加的队列为HTB队列,命令最后的"default 11"是htb特有的队列参数,意思是所有未分类的流量都将分配给类别1:11。
==》tc qdisc add dev xgbe0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8;为网卡xbge0创建一个cbq队列,限制网卡总带宽为100Mbit/s,avpkt表示平均包大小,单位字节,avpkt 1000表示平均包大小为1000B,cell表示一个数据包被发送出去的平均时间,通常设置为8,必须是2的整数次幂
2)为根队列创建相应的类别,对于句柄编号一般根队列为一位数,子类别为两位数
有关类别的TC 命令的一般形式为:
# tc class [add | change | replace] dev DEV parent qdisc-id [classid class-id] qdisc [qdisc specific parameters]
可以利用下面这三个命令为根队列1创建三个类别,分别是1:11、1:12和1:13,它们分别占用40、40和20mbit的带宽。
tc class add dev eth1 parent 1: classid 1:11 htb rate 40mbit ceil 40mbit
tc class add dev eth1 parent 1: classid 1:12 htb rate 40mbit ceil 40mbit
tc class add dev eth1 parent 1: cllassid 1:13 htb rate 20mbit ceil 20mbit
命令中,"parent 1:"表示类别的父亲为根队列1: 。"classid1:11"表示创建一个标识为1:11的类别,"rate 40mbit"表示系统将为该类别确保带宽40mbit,"ceil 40mbit",表示该类别的最高可占用带宽为40mbit。
3)为各个类别设置过滤器
有关过滤器的TC 命令的一般形式为:
# tc filter [add | change | replace] dev DEV [parent qdisc-id | root] protocol protocol prio priority filtertype [filtertype specific parameters] flowid flow-id
比如,需要将WWW、E-mail、Telnet三种流量分配到三个类别,即上述1:11、1:12和1:13,因此,需要创建三个过滤器,如下面的三个命令:
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 80 0xffff flowid 1:11
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 25 0xffff flowid 1:12
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 23 oxffff flowid 1:13
这里,"protocol ip"表示该过滤器应该检查报文分组的协议字段。"prio 1"表示它们对报文处理的优先级是相同的。对于不同优先级的过滤器,系统将按照从小到大的优先级顺序来执行过滤器,对于相同的优先级,系统将按照命令的先后顺序执行。这几个过滤器还用到了u32选择器(命令中u32后面的部分)来匹配不同的数据流。以第一个命令为例,判断的是dport字段,如果该字段与0xffff进行与操作的结果是80,则"flowid 1:11"表示将把该数据流分配给类别1:11。更加详细的有关TC的用法可以参考TC的手册页。
4)查看当前网卡上配过的流量控制规则
# tc[-s | -d ] qdisc show [ dev DEV ] tc -s qdisc show dev eth1
# tc[-s | -d ] class show dev DEV
# tc filter show dev DEV
# tc -s -d qdisc ls
5)删除已配置的规则
# tc qdisc del dev eth1 root
##实际项目使用场景篇##
1)配合netem模块对特定ip或port模拟超时(netem 是 Linux2.6 及以上内核版本提供的一个网络模拟功能模块。该功能模块可以用来在性能良好的局域网中,模拟出复杂的互联网传输性能,诸如低带宽、传输延迟、丢包等等情况。tc 可以用来控制 netem 的工作模式,也就是说,如果想使用 netem ,需要至少两个条件,一个是内核中的 netem 功能被包含,另一个是要有 tc 。)##亲测有效##
# tc qdisc add dev xgbe0 root netem delay 100ms ##这个是对整个网卡xgbe0的数据包延迟100ms发送。如果要对发送到特定ip或从特定端口发送的数据包延迟100ms,再加下面的命令设置class和filter。
# tc class add dev xgbe0 parent 1: classid 1:11
# tc filter add dev xgbe0 parent 1:0 protocol ip prio 1 u32 match ip dst 10.10.10.91 flowid 1:1 ##到特定ip
# tc filter add dev xgbe0 parent 1:0 protocol ip prio 1 u32 match ip dport 9988 flowid 1:1 ##从特定port发出的
2)模拟丢包
# tc qdisc add dev eth0 root netem loss 1%
该命令将eth0网卡的传输设置为随机丢掉1%的数据包,也是对整个网卡有效,如果也是要特定ip或port试着按上述进行配置class和filter
也可以设置丢包的成功率:
# tc qdisc add dev eth0 root netem loss 1% 30%
该命令将eth0网卡的传输设置为随机丢掉1%的数据包,成功率为30%。
3)模拟包损坏 ##没试过##
# tc qdisc add dev eth0 root netem corrupt 0.2%
该命令将eth0网卡的传输设置为随机产生0.2%的损坏的数据包 。 (内核版本需在2.6.16以上)
4)模拟包乱序
# tc qdisc change dev eth0 root netem delay 10ms reorder 25% 50%
该命令将eth0网卡的传输设置为:有25%的数据包(50%相关)会被立即发送,其他的延迟10ms。
新版本中,如下命令也会在一定程度上打乱发包的次序:
# tc qdisc add dev eth0 root netem delay 100ms 10ms
5)模拟包重复
# tc qdisc add dev eth0 root netem duplicate 1%
该命令将eth0网卡的传输设置为随机产生1%的重复数据包 。
6)模拟网络抖动
可以写个脚本进行loop:先tc命令设置好延时——》隔随机时间后,将tc规则删除-->再隔随机时间后,tc命令加入延时如此往复
脚本运行期间就可以看服务在网络抖动时整体时延或资源消耗是否符合预期或是否出现服务异常warning日志等。
##使用之中遇到的几个问题##
1)tc执行必须root账号;只针对出口流量有效
2)如果机器是64位,执行tc之前先创建一个软链,不然在用netem库时会出现错误『[Netem] Unknown qdisc "netem"』:ln -s /usr/lib64/tc/ /usr/lib/tc
参考:
1. linux下流量控制工具TC详细说明及应用实例 写得很赞的一篇博文