2012年8月20日星期一

CBQ限速

CBQ(Class based Queuing)是classful的限速工具。CBQ的主要工作原理是调整包之间的时间间隔来达到限速的目的。比如10mbit/s的链路要限制为1mbit/s,那么就有90%的时间是空闲的。这种方式需要预先的知道链路的capacity。

原理:

CBQ会统计链路的idle时间(moving_avg),并将这个同理论计算的idle时间比较,idle_moving_avg - idle_target = avgidle,理想情况下avgidle是0,如果链路过载,那么avgidle就是负值,CBQ会限制发送一段时间,如果长时间不发生数据,那么avgidle就会变大,这种情况下就会有一些burst,为了限制burst,就需要设置maxidle.

idle时间的衡量在实现中是用的设备驱动的数据请求之间的jiffies.

参数:

avgpkt - 包的平均大小,字节数。这个用来计算maxidle。

bandwidth - 链路的capacity,用来计算理论idle时间

cell - 计算包的传输时延时用到,cell作为包大小的基本单位,默认为8。例如:800byte和806byte的包的传输时延都一样。

maxburst - 突发流量的设置,这里是设置包的个数,maxidle不能直接设置,只能通过这个参数设置。

minburst - CBQ在流量过载时,理想情况下是在计算的每个idle时间点只发送一个包,但内核的时间精度有限制,所以只能选择在相对长一点的时间内多一次性的多发送一些数据包。minburst设置的越大,那么在长时间内的流控就越准,但会带来瞬间的突发流量。

minidle - CBQ在流量过载时,avgidle小于0,再次发生数据要等到avgidle恢复到某个比较大的值,如果之前的流量有很大的突发,这段时间可能会很长。如果指定minidle,就可以防止avgidle出现过小的情况。Minidle的单位是us(microseconds), 设置为10表示-10us。

mpu - 最小包单元的字节数,因为即便payload是0, ethernet的包长度必须填充为64字节,也是需要时间来传输的,这个用来精确的计算idle时间。

rate - 要限制的带宽。

CBQ的class特性:

CBQ也可以组织成树形结构,每个class是一个节点,可以设置优先级,优先级小的优先调度,调度采用WWR(weighted round robin)方式,下面是相关的一些参数:

allot - 每次调度可以发送的字节数(最小单元)。一个class一轮可以调度多次,根据weight来。

prio - 优先级

weight - 权值,最终会做归一化处理,一般采用10分制。renormalized weight和alloc的乘积就是每轮调度该class能发生的字节数。

CBQ的带宽共享:

isolated - 不借给子节点class带宽

sharing - 可以借给字节的class带宽,默认值。

bounded - 不去借用父节点class带宽

borrow - 可以借用父节点class带宽,默认值。


例子:

               1:           root qdisc
               |
              1:1           child class
             /   \
            /     \
          1:3     1:4       leaf classes
           |       |
          30:     40:       qdiscs
         (sfq)   (sfq)
 
在这个例子中,给http 5mbit,给smtp 3mbit,他们加起来不超过6 mbit/s, 并且他们直接可以共享带宽。
链路的capacity是100mbit。
 
1)设置root节点,设置为bounded那么带宽就不会超出6 mbit.
 
# tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit         \
  avpkt 1000 cell 8
# tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit  \
  rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20      \
  avpkt 1000 bounded 
 
2) 设置两个叶子节点:
 
# tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit  \
  rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20      \
  avpkt 1000                       
# tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit  \
  rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20      \
  avpkt 1000 

4)采用SFQ替换FIFO,达到流间调度的公平性。
 
# tc qdisc add dev eth0 parent 1:3 handle 30: sfq
# tc qdisc add dev eth0 parent 1:4 handle 40: sfq
 
5)加入过滤,针对特定的协议端口:
 
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
  sport 80 0xffff flowid 1:3
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
  sport 25 0xffff flowid 1:4 
 
 
工具: 

CentOS/Redhat默认已经带了一个cbq的工具,相关的配置在/etc/sysconf/cbq,shell脚本在sbin/cbq下.