Traffic control
简介
在linux环境下,可以利用tc命令工具对本地流量进行控制,主要通过限速(shaping),调度(scheduling)和策略(policing)进行流量的控制。
本文主要简略介绍tc中所使用到的几个概念,并结合命令示例对流量控制进行解释。由于tc主要用于出带宽的控制,所以下文主要描述的都是对出带宽的控制,文末附加一个利用tc进行入带宽控制的示例。
tc主要利用3种对象来达成对流量的控制,分别是qdisc(排队规则), class(类别), filter(分类器)。
qdisc
qdisc可以看做是一个有规则的队列,内核如果需要网卡向外发送数据,首先需要放入队列中,然后内核从队列中取出。例如最简单的fifo队列,数据包通过这个队列会按照先进先出的顺序从队列中流出发送到网卡上。
qdisc按照类别划分可以分为有类别队列和无类别队列,其中有类别队列本身附着有类属性,并会根据分类器划分到类中,类可以继续划分为新的子类,如果不在继续分类,则需要为类指定一个队列。按照层次关系形成一棵类似于树状的结构,且树的叶子类节点需要附着一个无类型的队列。
常见的无类别队列有sfq(随机公平队列),pfifo_fast,tbf(令牌桶)。
- sfq
sfq实现了高度的公平性,会为每个会话使用一个散列算法散列到有限的几个队列中,系统每次从每个队列中拿出流量进行发送。多个会话可能共享一个队列,sfq算法会定期更新散列算法,重新将会话放到新的队列中来达到随机的效果。
1 | 增加一个qdisc,父类为1:10,其自身ID为10:0,使用sfq,每10秒更换一次hash算法 |
- pfifo_fast
pfifo_fast队列可以看作是有类别队列prio的无类别(固定类别)版本,该队列规则内部已经定义了优先级且无法使用tc进行修改。
pfifo_fast内部有3个band,分别记为0,1,2。如果band0上还有数据包,则一直从这个band上取出直到没有后再去band1,以此类推。数据包是按照header中的服务类型TOS进行分配的。TOS是数据包上的一个4bit字段,具体规则如下(规则源自lartc):
1 | Binary Decimcal Meaning |
- tbf
tbf队列利用令牌桶原理来控制出带宽,每流出一定的数据量,就需要消耗桶中的令牌,一旦令牌消耗完毕,则不会再继续发送数据。每个一段时间,会重新往桶里面添加令牌直到桶满为止。
1 | tc qdisc add dev eth0 root tbf rate 0.5mbit \ |
常见的分类队列有prio和htb
- prio
prio队列与前面的pfifo_fast类似,高优先级的数据先发送。在创建prio时,系统默认就会创建3个类,这些类仅包含单纯的fifo队列,用户可以利用tc进行替换。
- htb
htb(Hierarchical Token Bucket)分层桶令牌与无类队列tbf类似,用于流量整形。
1 | 速率为30kbps,且上限(ceil)为100kps,说明如果网络空闲,这个class可以向外界借用宽带,默认ceil为rate一致 |
htb可以进行优先级划分,高优先级的队列优先得到剩余宽带,同优先级之间按照rate进行按比例划分。
class
class存在于有类别队列中,class是可以包含多个子类或者一个子队列。叶子类在队列中属于最终类别,会默认包含一个fifo的qdisc。
filter
filter的作用主要是定义如何将一个qdisc(class)划分到子class中。常见的分类器有u32。可以根据ip, 端口,协议类型,mac地址等进行过滤。
样例说明
在实际使用tc命令进行流量控制时,会为每个qdisc/class分配一个id,id由 主ID:从ID 两部分组成,其中qdisc的命名以主ID进行区分,例如 10: ,别是其ID为10:0,qdisc的从ID都是0。class的ID为10:1,其中主ID需要于其父节点ID一致。
出带宽控制
下面的例子来自Linux高级流控
1 | 创建htb,默认走1:30的类别 |
另外,使用以下命令可以查看各个qdisc/class的流量情况:
1 | tc -s -d qdisc show dev eth0 |
tc + cgroup
可以利用cgroup来进行进程的流量控制。使用cgroup进行流量控制时,需要引入net_cls cgroup子模块,在net_cls.classid文件中定义好该group下进程的分类class id。并在定义filter时使用cgroup filter
1 | tc filter add dev eth2 parent 10: protocol ip prio 10 handle 1: cgroup |
入带宽控制
一般使用tc进行出带宽控制,因为tc的入带宽控制从网卡拿数据时数据已经发送到本机,再进行控制显得没有太多意义。下面仅演示利用tc ingress进入入带宽控制
1 | tc qdisc add dev eth0 handle ffff: ingress |
其他
流量测试数据可以使用 http://cachefly.cachefly.net/100mb.test 进行测试