
tc - 流量控制 (2/2)
上次我们说到了一些classless qdisc,一般单独用或者作为其他classfull qdisc的leaf qdisc。
这次我们就要大概描述下classful qdisc
概念
class & filter
classful和classless听起来很像我们常说的stateful stateless,有/无状态的,classful/classless qdisc就是带分类的队列策略,而具体的分类方法就是filter。
遇到classful qdisc时,每个包到达设备上的root qdisc后,总是先通过filter一层层分类,分类为具体的class后,最后推入具体的leaf qdisc。而出队时,内核总是和root qdisc取数据包,然后root qdisc通过递归遍历子qdisc来决定具体送出哪一个数据包。
we define some classfull qdisc on a device and it could look like this:
(every x: is a qdisc, and x:y is a class)
qdisc class qdisc class
^ ^ ^ ^
/- 10:0
- 1:1 - 10: -> (filter) --- 10:1
/ \- 10:2
root 1: -> (filter) --- 1:2
\
- 1:3
handle
上面的结构里面,有两种节点,一种是x:,一种是x:y。
x:y是具体的qdisc的class,x:是qdisc的handle,用来说明class和qdisc之间的从属关系。
常用的qdisc
这两天刚刚好用到了一些,比如说prio
prio
Background
有的时候机器进出的流量很大,会造成有一些对时间敏感的服务超时。
比如说我们在两个物理机之间跑iperf3:
# one host
$ iperf3 -s
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
......
# another host
$ iperf3 -c 192.168.2.181 -t 10000 -u -M 30 -b 0 -P 100
......
[187] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[189] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[191] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[193] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[195] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[197] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[199] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[201] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[203] 3.00-4.00 sec 7.65 MBytes 64.2 Mbits/sec 5540
[SUM] 3.00-4.00 sec 765 MBytes 6.42 Gbits/sec 554000
......
这个时候运行访问redis,redis总是会超时的:
$ while true; do echo start $(date); redis-cli -h 192.168.2.181 keys '*'; echo done $(date); sleep 1; done
......
start 2019年 12月 25日 星期三 20:47:39 CST
Could not connect to Redis at 192.168.2.181:6379: Connection timed out
done 2019年 12月 25日 星期三 20:47:43 CST
......
prio
prio是一个比较简单的qdisc,把流量分为bands(默认为3)个优先级,对应bands个class,每个class是一个pfifo_fast,同时配置priomap。你要是自己设置bands的数量,就要自己配置priomap。不过一般默认的就够了。
逻辑基本上和pfifo_fast一样,只不过可以通过class指定某些数据包的优先级。
solution
# create a prio qdisc with handle 1:
$ sudo tc qdisc add dev enp6s0 root handle 1: prio
# classfy packets to 6379 to class 1:1(highest)
$ sudo tc filter add dev enp6s0 protocol ip parent 1: prio 1 u32 match ip dport 6379 0xffff flowid 1:1
# classfy packets to 5201 to class 1:2(higher)
$ sudo tc filter add dev enp6s0 protocol ip parent 1: prio 1 u32 match ip dport 5201 0xffff flowid 1:2
然后我们再尝试redis,就很正常了
$ while true; do echo start $(date); redis-cli -h 192.168.2.181 keys '*'; echo done $(date); sleep 1; done :(
start 2019年 12月 25日 星期三 20:57:02 CST
1) "abc"
done 2019年 12月 25日 星期三 20:57:02 CST
start 2019年 12月 25日 星期三 20:57:03 CST
1) "abc"
done 2019年 12月 25日 星期三 20:57:03 CST
start 2019年 12月 25日 星期三 20:57:04 CST
1) "abc"
done 2019年 12月 25日 星期三 20:57:04 CST
HTB
HTB逻辑上基于TBF。但是HTB允许你创建一个属性的结构,每一个节点是一个class,每个class是一个TBF。每一个节点可以限制速率、最大速率和权。
和之前博客里面提到的 TBF 不大一样的是。每个leaf在耗尽token之后,还会从他的父亲节点借token。这样就可以做到各个class都高带宽时按照各自的限制限速,只有个别class满负载的情况下占用从子节点到根节点的全部带宽。
配置略微有点复杂,但是也没复杂到哪里去。但是我觉得Debian上讲的更清楚:
Debian Wiki的TrafficControl页 Wayback machine的归档
其他qdisc
还要很多其他classful qdisc,比如说mq、cbq之类的,都和上面两个差不多。