感谢支持
我们一直在努力

Linux流量控制(SFQ/TBFPRIO/CBQ/HTB原理介绍)

Linux流量控制控发不控收,所以只能对产生瓶颈网卡处的发包速率进行控制..而网络瓶颈分析亦为Linux网络流控的第一步。


二种流控算法上分:


无类算法 用于树叶级无分支的队列 SFQ TBF pFIFO


分类算法 用于多分支的队列 PRIO HTB CBQ


调度


在分类器的帮助下,一个队列规定可以裁定某些数据包可以排在其他数据包之前发送。这种处理叫做“调度”,比如此前提到的pfifo_fast就是这样的。调度也可以叫做“重排序”,但这样容易混乱。


整形


在一个数据包发送之前进行适当的延迟,以免超过事先规定好的最大速率,这种处理叫做“整形”。整形在出对处进行。习惯上,通过丢包来降速也经常被称为整形。


1 pfifo_fast


这个队列的特点就象它的名字——先进先出(FIFO),也就是说没有任何数据包被特殊对待。至少不是非常特殊。


这个队列有3个所谓的“频道”。FIFO规则应用于每一个频道。并且:如果在0频道有数据包等待发送,1频道的包就不会被处理,1频道和2频道之间的关系也是如此。


内核遵照数据包的TOS标记,把带有“最小延迟”标记的包放进0频道。


不要把这个无类的简单队列规定与分类的PRIO相混淆!虽然它们的行为有些类似,但对于无类的pfifo_fast而言,你不能使用tc命令向其中添加其它的队列规定。


pfifo_fast队列规定作为硬性的缺省设置,你不能对它进行配置


2.队列控制的无类算法 SFQ


SFQ(Stochastic Fairness Queueing 随机公平队列)是公平队列算法家族中的一个简单实现.它的精确性不如其它的方法,但实现了高度的公平,需要的计算量亦很少。


SFQ算法主要针对一个TCP会话或者UDP流.流量被分成相当多数量的FIFO队列中,每个队列对应一个会话.数据按照简单轮转的方式发送, 每个会话都按顺序得到发送机会. 这种方式非常公平,保证了每一个会话都不会没其它会话所淹没.


SFQ之所以被称为”随机”,是因为它并不是真的为每一个会话创建一个队列,而是使用一个散列算法,把所有的会话映射到有限的几个队列中去. 因为使用了散列,所以可能多个会话分配在同一个队列里,从而需要共享发包的机会,也就是共享带宽.为了不让这种效应太明显,SFQ会频繁地改变散列算法, 以便把这种效应控制在几秒钟之内(时间由参数设定).


注:SFQ只会发生在数据发生拥堵,产生等待队列的网卡上..出口网卡若无等待队列,SFQ亦不起作用…


以下示例即在网卡上建立SFQ:


#tc qdisc add dev eth0 root handle 1: sfq


SFQ参数有perturb(重新调整算法间隔) quantum 基本上不需要手工调整:


perturb


多少秒后重新配置一次散列算法。如果取消设置,散列算法将永远不会重新配置(不建议这样做)。10秒应该是一个合适的值。


quantum


一个流至少要传输多少字节后才切换到下一个队列。却省设置为一个最大包的长度(MTU的大小)。不要设置这个数值低于MTU!


handle 1: 规定算法编号.


#tc qdisc sh dev eth0 显示算法


#tc qdisc del dev eth0 root 删除 注:默认eht0支持TOS


SFQ队列一般用在树叶级,配合其它流量整形算法一并使用。

3.流量控制的无类算法 TBF


令牌桶过滤器(TBF)是一个简单的队列规定:只允许以不超过事先设定的速率到来的数据包通过,但可能允许短暂突发流量朝过设定值.


TBF很精确,对于网络和处理器的影响都很小,实现是针对数据的字节数进行的,而不是针对数据包进行,常用于网关限速.


TBF的实现在于一个缓冲器(桶),不断地被一些叫做”令牌”的虚拟数据以特定速率填充着. (token rate).桶最重要的参数就是它的大小,也就是它能够存储令牌的数量. 每个到来的令牌从数据队列中收集一个数据包,然后从桶中被删除.这个算法关联到两个流上——令牌流和数据流,于是我们得到3种情景:


A.数据流以等于令牌流的速率到达TBF.这种情况下,每个到来的数据包都能对应一个令牌,然后无延迟地通过队列.


B.数据流以小于令牌流的速度到达TBF.通过队列的数据包只消耗了一部分令牌,剩下的令牌会在桶里积累下来,直到桶被装满.剩下的令牌可以在需要以高于令牌流速率发送数据流的时候消耗掉,这种情况下会发生突发传输.


C.数据流以大于令牌流的速率到达TBF.这意味着桶里的令牌很快就会被耗尽.导致TBF中断一 段时间,称为”越限”.如果数据包持续到来,将发生丢包. 此种情况最重要,因为它可以用来对数据通过过滤器的速率进行整形. 令牌的积累可以导致越限的数据进行短时间的突发传输而不必丢包,但是持续越限的话会导致传输延迟直至丢包.


以下示例是在网卡建立TBF:


#tc qd add dev eth1 root handle 1: tbf rate 256kbit burst 10000 latency 50ms


速率256kbit 突发传输10k 最大延迟50ms


#tc -s qd sh dev eth1 统计


#tc qd del dev eth1 root 删除


rate 限制的传输速率 用位来计算


latency 确定了一个包在TBF中等待传输的最长等待时间.


burst 桶的大小,以字节计.指定了最多可以有多少个令牌能够即刻被使用.


注:管理的带宽越大,需要的缓冲器就越大.在Intel体系上,10兆bit/s的速率需要至少10k字节的缓冲区


才能达到期望的速率. 缓冲区太小导致潜在的丢包.


分类算法PRIO/CBQ/HTB


分类算法主要作用是可以对多种数据流区别对待.一旦数据包进入一个分类的队列规定,它就得被送到某一个类中分类,对数据包进行分类的工具是过滤器.过滤器会返回一个决定,队列规定就根据这个决定把数据包送入相应的类进行排队.每个子类都可以再次使用它们的过滤器进行进一步的分类.直到不需要进一步分类时,数据包才进入该类包含的队列规定排队. 除了能够包含其它队列规定之外,绝大多数分类的队列规定能够流量整形


注:过滤器对数据包进行分类的工具,是从队列规定内部调用的,而不是从别处.(用在分叉的分支上)


列规定家族:根,句柄,兄弟和父辈


每块网卡都有一个出口”根队列规定”,缺省情况下是前面提到的pfifo_fast队列规定.每个队列规定都指定一个句柄,以便以后的配置语句能够引用这个队列规定.除了出口队列规定之外,每块网卡还有一个入口,以便policies进入的数据流.


队列规定的句柄有两个部分:一个主号码和一个次号码.习惯上把根队列规定称为”1:”,等价于”1:0″.队列规定的次号码永远是0.类的主号码必须与它们父辈的主号码一致.

数据包如何出队并交给硬件


当内核决定把一个数据包发给网卡的时候,根队列规定1:会得到一个出队请求,然后把它传给1:1,然后依次传给10:,12:和13:(子类自定义),然 后试图从它们中进行dequeue()操作.也就是说,内核需要遍历整颗树, 换句话说,类及其兄弟仅仅与其”父队列规定”进行交谈,而不会与网卡进行交谈.只有根队列规定才能由内核进行出队操作!更进一步,任何类的出队操作都不会 比它们的父类更快.我们可以把SFQ作为一个子类,放到一个可以进行流量整形的父类中,从而能够同时得到SFQ的调度功能和其父类的流量整形功能.


1.队列控制的分类算法 PRIO


PRIO分类优先算法(从左至右优先发包),队列规定并不进行整形,它仅仅根据你配置的过滤器把流量进一步细分.你可以认为PRIO队列规定是pfifo_fast的一种衍生物,区别在每个频道都是一个单独的类,而非简单的FIFO.


当数据包进入PRIO队列规定后,将根据你给定的过滤器设置选择一个类.缺省情况下有三个类,这些类仅包含纯FIFO队列规定而没有更多的内部结构.你可 以把它们替换成你需要的任何队列规定. 每当有一个数据包需要出队时,首先处理:1类.只有当标号更小的类中没有需要处理的包时,才会标号大的类.


PRIO配置范例:


大批量数据使用30:,交互数据使用20:或10:.


命令如下:


#tc qdisc add dev eth0 root handle 1: prio


#此命令立即创建了类: 1:1, 1:2, 1:3 (缺省三个子类)


#tc qdisc add dev eth0 parent 1:1 handle 10: sfq


#tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000


注:此为TBF限速的另一写法,前文有讲解.


#tc qdisc add dev eth0 parent 1:3 handle 30: sfq


主要参数有:(后续有实例)


bands 创建频道的数目.每个频道实际上就是一个类 跟priomap参数配合使用


注:频道是类,缺省情况下命名为主标号:1到主标号:3.如果你的PRIO队列规定是12:,把数据包过滤到


12:1将得到最高优先级. 0频道的次标号是1!1频道的次标号是2,以此类推.


priomap 给tc提供过滤器,如不提供PRIO队列规定将参考TC_PRIO的优先级来决定如何给数据包入队.


2.流量整形的分类算法 CBQ


CBQ的工作机制是确认链路的闲置时间足够长,以达到降低链路实际带宽的目的.为此,它要计算两个数据包的平均发送间隔.操作期间,有效闲置时间的测量使 用EWMA(exponential weighted moving average,指数加权移动均值)算法,也就是说最近处理的数据包的权值比以前的数据包按指数增加.UNIX的平均负载也是这样算出来的. 计算出来的平均时间值减去EWMA测量值,得出的结果叫做”avgidle”.最佳的链路负载情况下,这个值应当是0:数据包严格按照计算出来的时间间隔 到来. 在一个过载的链路上,avgidle值应当是负的.如果这个负值太严重,CBQ就会暂时禁止发包,称为”overlimit”(越限). 相反地,一个闲置的链路应该有很大avgidle值,这样闲置几个小时后,会造成链路允许非常大的带宽通过.为了避免这种局面,我们用maxidle来限avgidle


的值不能太大.


理论上讲,如果发生越限,CBQ就会禁止发包一段时间(长度就是事先计算出来的传输数据包之间的时间间隔),然后通过一个数据包后再次禁止发包.


配置范例:WEB服务器的流量控制为5Mbps,SMTP流量控制在3Mbps上.而且二者一共不得超过6Mbps,互相之间允许借用带宽


#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


这部分按惯例设置了根为1:0,并且绑定了类1:1.也就是说整个带宽不能超过6Mbps.


#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


建立了2个类.注意我们如何根据带宽来调整weight参数的.两个类都没有配置成”bounded”,但它们都连


接到了类1:1上,而1:1设置了”bounded”.所以两个类的总带宽不会超过6Mbps.别忘了,同一个CBQ下面的子


类的主号码都必须与CBQ自己的号码相一致!


#tc qdisc add dev eth0 parent 1:3 handle 30: sfq


#tc qdisc add dev eth0 parent 1:4 handle 40: sfq


缺省情况下,两个类都有一个FIFO队列规定.但是我们把它换成SFQ队列,以保证每个数据流都公平对待.


#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


CBQ流量整形算法相对比较复杂,工作中还常用…示例中的各参数请参阅:HOWTO中文文档


3.流量整形的分类算法 HTB


HTB(Hierarchical Token Bucket)分层的令牌桶一个分类的令牌桶过滤器,工作原理和相关配置同于TBF..拥有TBF的各项性能,可参阅TBF的工作细节…


配置范例:环境与要求同上述CBQ的例子


#tc qdisc add dev eth0 root handle 1: htb default 30


#tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k


#tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k


#tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k


#tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k


#tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10


#tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10


#tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10


#添加过滤器,直接把流量导向相应的类:


#U32=”tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32″


#$U32 match ip dport 80 0xffff flowid 1:10


#$U32 match ip sport 25 0xffff flowid 1:20


关于什么时候用哪种队列的建议


? 如果想单纯地降低出口速率,使用令牌桶过滤器。调整桶的配置后可用于控制很高的带宽。


? 如果你的链路已经塞满了,而你想保证不会有某一个会话独占出口带宽,使用随机公平队列。


? 如果你有一个很大的骨干带宽,并且了解了相关技术后,可以考虑前向随机丢包(参见“高级”那一章)。


? 如果希望对入口流量进行“整形”(不是转发流量),可使用入口流量策略,注意,这不是真正的“整形”。


? 如果你正在转发数据包,在数据流出的网卡上应用TBF。除非你希望让数据包从多个网卡流出,也就是说入口网卡起决定性作用的时候,还是使用入口策略。


? 如果你并不希望进行流量整形,只是想看看你的网卡是否有比较高的负载而需要使用队列,使用pfifo队列(不是pfifo_fast)。它缺乏内部频道但是可以统计backlog。

赞(0) 打赏
转载请注明出处:服务器评测 » Linux流量控制(SFQ/TBFPRIO/CBQ/HTB原理介绍)
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏