此文已由作者刘超授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
对于控制一台机器的QoS,分两个方向,一个是入方向,一个是出方向。
其实能控制的只有出方向,通过Shaping,将出的流量控制成自己想要的模样。而进入的方向是无法控制的,只能通过Policy将包丢弃。
OpenVwitch中有关QoS的表结构如下:
我们可以通过TC控制网络的QoS,主要通过队列的方式。
第一大类称为Classless Queuing Disciplines,默认为pfifo_fast,是一种不把网络包分类的一种技术。
pfifo_fast根据网络包中的TOS对应的数字,在TOS的priomap中查看对应的Band,不同的Band对应的不同的队列。
另外一种称为SFQ, Stochastic Fair Queuing
有很多的FIFO的队列,TCP Session或者UDP stream会被分配到某个队列。包会RoundRobin的从各个队列中取出发送。
这样不会一个Session占据所有的流量。
但不是每一个Session都有一个队列,而是有一个Hash算法,将大量的Session分配到有限的队列中。
这样两个Session会共享一个队列,也有可能互相影响。
Hash函数会经常改变,从而session不会总是相互影响。
还有一种是TBF, Token Bucket Filter。两个概念Tokens and buckets,所有的包排成队列进行发送,但不是到了队头就能发送,而是需要拿到Token才能发送。
Token根据设定的速度rate生成,所以即便队列很长,也是按照rate进行发送的。
当没有包在队列中的时候,Token还是以既定的速度生成,但是不是无限累积的,而是放满了buckets为止,篮子的大小常用burst/buffer/maxburst来设定。
Buckets会避免下面的情况:当长时间没有包发送的时候,积累了大量的Token,突然来了大量的包,每个都能得到Token,造成瞬间流量大增。
另外一大类是Classful Queuing Disciplines。
其中典型的为HTB, Hierarchical Token Bucket。
Shaping:仅仅发生在叶子节点,依赖于其他的Queue。
Borrowing: 当网络资源空闲的时候,借点过来为我所用。
Rate:设定的发送速度。
Ceil:最大的速度,和rate之间的差是最多能向别人借多少。
type of class |
class state |
HTB internal state |
action taken |
leaf |
< rate |
HTB_CAN_SEND |
Leaf class will dequeue queued bytes up to available tokens (no more than burst packets) |
leaf |
> rate, < ceil |
HTB_MAY_BORROW |
Leaf class will attempt to borrow tokens/ctokens from parent class. If tokens are available, they will be lent in quantum increments and the leaf class will dequeue up to cburst bytes |
leaf |
> ceil |
HTB_CANT_SEND |
No packets will be dequeued. This will cause packet delay and will increase latency to meet the desired rate. |
inner, root |
< rate |
HTB_CAN_SEND |
Inner class will lend tokens to children. |
inner, root |
> rate, < ceil |
HTB_MAY_BORROW |
Inner class will attempt to borrow tokens/ctokens from parent class, lending them to competing children in quantum increments per request. |
inner, root |
> ceil |
HTB_CANT_SEND |
Inner class will not attempt to borrow from its parent and will not lend tokens/ctokens to children classes. |
接下来举个具体的例子,通过TC构建一个如下的HTB树。
创建一个HTB的qdisc在eth0上,句柄为1:,default 12表示默认发送给1:12。
tc qdisc add dev eth0 root handle 1: htb default 12
创建一个root class,然后创建几个子class。
同一个root class下的子类可以相互借流量,如果直接不在qdisc下面创建一个root class,而是直接创建三个class,他们之间是不能相互借流量的。
tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps
创建叶子qdisc,分别为fifo和sfq。
tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 5
tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5
tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10
设定规则:从1.2.3.4来的,发送给port 80的包,从1:10走;其他从1.2.3.4发送来的包从1:11走;其他的走默认。
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 match ip dport 80 0xffff flowid 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 flowid 1:11
更多网易技术、产品、运营经验分享请点击。