概述
令牌桶过滤器(TBF)
令牌桶过滤器(TBF)是一个简单的队列规定:只允许以不超过事先设定的速率到来的数据包通过,但可能允许短暂突发流量朝 过设定值.TBF很精确,对于网络和处理器的影响都很小.所以如果您想对一个网卡限速,它应该成为您的第一选择!TBF的实现在于一个缓冲器(桶),不断 地被一些叫做"令牌"的虚拟数据以特定
速率填充着. (token rate).桶最重要的参数就是它的大小,也就是它能够存储令牌的数量.每个到来的令牌从数据队列中收集一个数据包,然后从桶中被删除.这个算法关联到两个流上——令牌流和数据流,于是我们得到3种情景:
1.数据流以等于令牌流的速率到达TBF.这种情况下,每个到来的数据包都能对应一个令牌,然后无延迟地通过队列.
2.数据流以小于令牌流的速度到达TBF.通过队列的数据包只消耗了一部分令牌,剩下的令牌会在桶里积累下来,直到桶被装满.剩下的令牌可以在需要以高于令牌流速率发送数据流的时候消耗掉,这种情况下会发生突发传输.
3. 数据流以大于令牌流的速率到达TBF.这意味着桶里的令牌很快就会被耗尽.导致TBF中断一段时间,称为"越限".如果数据包持续到来,将发生丢包.最后 一种情景非常重要,因为它可以用来对数据通过过滤器的速率进行整形.令牌的积累可以导致越限的数据进行短时间的突发传输而不必丢包,但是持续越限的话会导 致传输延迟直至丢包.请注意,实际的实现是针对数据的字节数进行的,而不是针对数据包进行的.
9.2.2.1. 参数与使用
即使如此,你还是可能需要进行修改,TBF提供了一些可调控的参数.第一个参数永远可用:
limit/latency
limit确定最多有多少数据(字节数)在队列中等待可用令牌.你也可以通过设置latency参数来指定这个参数,latency参数确定了一个包在TBF中等待传输的最长等待时间.后者计算决定桶的大小,速率和峰值速率.
burst/buffer/maxburst
桶 的大小,以字节计.这个参数指定了最多可以有多少个令牌能够即刻被使用.通常,管理的带宽越大,需要的缓冲器就越大.在Intel体系上,10兆 bit/s的速率需要至少10k字节的缓冲区才能达到期望的速率.如果你的缓冲区太小,就会导致到达的令牌没有地方放(桶满了),这会导致潜在的丢包.
mpu
一个零长度的包并不是不耗费带宽.比如以太网,数据帧不会小于64字节.Mpu(Minimum Packet Unit,最小分组单位)决定了令牌的最低消耗.
rate
速度操纵杆.参见上面的limits!如果桶里存在令牌而且允许没有令牌,相当于不限制速率(缺省情况).If the
bucket contains tokens and is allowed to empty, by default it does so at infinite speed.
如果不希望这样,可以调整入下参数:
peakrate
如 果有可用的令牌,数据包一旦到来就会立刻被发送出去,就象光速一样.那可能并不是你希望的,特别是你有一个比较大的桶的时候.峰值速率可以用来指定令牌以 多块的速度被删除.用书面语言来说,就是:释放一个数据包,但后等待足够的时间后再释放下一个.我们通过计算等待时间来控制峰值速率然而,由于UNIX定 时器的分辨率是10毫秒,如果平均包长10k bit,我们的峰值速率被限制在了1Mbps.
mtu/minburst
但是如果你的常规 速率比较高,1Mbps的峰值速率对我们就没有什么价值.要实现更高的峰值速率,可以在一个时钟周期内发送多个数据包.最有效的办法就是:再创建一个令牌 桶!这第二个令牌桶缺省情况下为一个单个的数据包,并非一个真正的桶.要计算峰值速率,用mtu乘以100就行了. (应该说是乘以HZ数,Intel
体系上是100,Alpha体系上是1024)
9.2.2.2. 配置范例
这是一个非常简单而实用的例子:
# tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540
为 什么它很实用呢?如果你有一个队列较长的网络设备,比如DSL modem或者cable modem什么的,并通过一个快速设备(如以太网卡)与之相连,你会发现上载数据绝对会破坏交互性.这是因为上载数据会充满modem的队列,而这个队列 为了改善上载数据的吞吐量而设置的特别大.但这并不是你需要的,你可能为了提高交互性而需要一个不太大的队列.也就是说你希望在发送数据的时候干点别的事 情.上面的一行命令并非直接影响了modem中的队列,而是通过控制Linux中的队列而放慢了发送数据的速度.把220kbit修改为你实际的上载速度 再减去几个百分点.如果你的modem确实很快,就把"burst"值提高一点.
9.2.3. 随机公平队列(SFQ)
SFQ(Stochastic Fairness Queueing,随机公平队列)是公平队列算法家族中的一个简单实现.它的精确性不如其它的方法,但是它在实现高度公平的同时,需要的计算量却很少.SFQ的关键词是"会话"(或称作
" 流") ,主要针对一个TCP会话或者UDP流.流量被分成相当多数量的FIFO队列中,每个队列对应一个会话.数据按照简单轮转的方式发送, 每个会话都按顺序得到发送机会.这种方式非常公平,保证了每一个会话都不会没其它会话所淹没.SFQ之所以被称为"随机",是因为它并不是真的为每一个会 话创建一个队列,而是使用一个散列算法,把所有的会话映射到有限的几个队列中去.因为使用了散列,所以可能多个会话分配在同一个队列里,从而需要共享发包 的机会,也就是共享带宽.为了不让这种效应太明显,SFQ会频繁地改变散列算法,以便把这种效应控制在几秒钟之内.有很重要的一点需要声明:只有当你的出 口网卡确实已经挤满了的时候,SFQ才会起作用!否则在你的Linux机器中根本就不会有队列,SFQ也就不会起作用.稍后我们会描述如何把SFQ与其它 的队列规定结合在一起,以保证两种情况下都比较好的结果.特别地,在你使用DSL modem或者cable modem的以太网卡上设置SFQ而不进行任何进一步地流量整形是无谋的!
9.2.3.1. 参数与使用
SFQ基本上不需要手工调整:
perturb
多少秒后重新配置一次散列算法.如果取消设置,散列算法将永远不会重新配置(不建议这样做).10秒应该是一个合适的值.
quantum
一个流至少要传输多少字节后才切换到下一个队列.却省设置为一个最大包的长度(MTU的大小).不要设置这个数值低于MTU!
9.2.3.2. 配置范例
如果你有一个网卡,它的链路速度与实际可用速率一致——比如一个电话MODEM——如下配置可以提高公平性:
# tc qdisc add dev ppp0 root sfq perturb 10
# tc -s -d qdisc ls
qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec
Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)
"800c:"这个号码是系统自动分配的一个句柄号,"limit"意思是这个队列中可以有128个数据包排队等待.一共可以有1024个散列目标可以用于速率审计,而其中128个可以同时激活.
(no more packets fit in the queue!)每隔10秒种散列算法更换一次.
9.3. 关于什么时候用哪种队列的建议
总之,我们有几种简单的队列,分别使用排序,限速和丢包等手段来进行流量整形.下列提示可以帮你决定使用哪一种队列.涉及到了第14章 所描述的的一些队列
规定:
1.如果想单纯地降低出口速率,使用令牌桶过滤器.调整桶的配置后可用于控制很高的带宽.如果你的链路 已经塞满了,而你想保证不会有某一个会话独占出口带宽,使用随机公平队列.
2.如果你有一个很大的骨干带宽,并且了解了相关技术后,可以考虑前向随机丢包(参见"高级"那一章).
3.如果希望对入口流量进行"整形"(不是转发流量),可使用入口流量策略,注意,这不是真正的"整形".
4.如果你正在转发数据包,在数据流出的网卡上应用TBF.除非你希望让数据包从多个网卡流出,也就是说入 口网卡起决定性作用的时候,还是使用入口策略.
5.如果你并不希望进行流量整形,只是想看看你的网卡是否有比较高的负载而需要使用队列,使用pfifo队列(不是pfifo_fast).它缺乏内部频道但是可以统计backlog.
6.最后,你可以进行所谓的"社交整形".你不能通过技术手段解决一切问题.用户的经验技巧永远是不友善的.正确而友好的措辞可能帮助你的正确地分配带宽!
9.4. 术语
为 了正确地理解更多的复杂配置,有必要先解释一些概念.由于这个主题的历史不长和其本身的复杂性,人们经常在说同一件事的时候使用各种词汇.以下来自 draft-ietf-diffserv-model-06.txt,Diffserv路由器的建议管理模型. 可以在以下地址找到:
http://www.ietf.org/internet-dra ... fserv-model-06.txt.关于这些词语的严格定义请参考这个文档.队列规定
管理设备输入(ingress)或输出(egress)的一个算法.
无 类的队列规定:一个内部不包含可配置子类的队列规定.分类的队列规定:一个分类的队列规定内可一包含更多的类.其中每个类又进一步地包含一个队列规定,这 个队列规定可以是分类的,也可以是无类的.根据这个定义,严格地说pfifo_fast算是分类的,因为它实际上包含3个频道(实际上可以认为是子类). 然而从用户的角度来看它是无类的,因为其内部的子类无法用tc工具进行配置.
类
一个分类的队列规定可以拥有很多类,类内包含队列规定.
分类器
每个分类的队列规定都需要决定什么样的包使用什么类进行发送.分类器就是做这个用的.
过滤器
分类是通过过滤器完成的.一个过滤器包含若干的匹配条件,如果符合匹配条件,就按此过滤器分类.
调度
在分类器的帮助下,一个队列规定可以裁定某些数据包可以排在其他数据包之前发送.这种处理叫做"调度",比如此前提到的pfifo_fast就是这样的.调度也可以叫做"重排序",但这样容易混乱.
整形
在一个数据包发送之前进行适当的延迟,以免超过事先规定好的最大速率,这种处理叫做"整形".整形在egress处进行.习惯上,通过丢包来降速也经常被称为整形.
策略
通过延迟或是丢弃数据包来保证流量不超过事先规定的带宽。在Linux,里,策略总是规定丢弃数据包而不是延迟。即,不存在ingress队列。
Work-Conserving
对于一个work-conserving队列规定,如果得到一个数据包,它总是立刻对它进行分发。换句话说,只要网卡(egress队列规定)允许,它就不会延迟数据包的发送。
non-Work-Conserving
有些队列——比如令牌桶过滤器——可能需要暂时停止发包以实现限制带宽。也就是说它们有时候即使有数据包需要处理,也可能拒绝发送。 现在我们简单了解了一些术语,让我们看看他们的位置:
用户级程序
^
|
+---------------+----------------------------------------------+
| Y |
| -------> IP 协议栈 |
| | | |
| | Y |
| | Y |
| ^ | |
| | / ----------> 转发--------> |
| ^ / | |
| |/ Y |
| | | |
| ^ Y /-队列规定1-/ |
| | Egress /----队列规定2-- / |
------>->Ingress 分类器 --队列规定3----|-- ->
| 队列规定 /_-队列规定4__/ |
| /--队列规定N_/ |
| |
+----------------------------------------------------------------+
最 左面的箭头表示从网络上进入机器的数据包.它们进入Ingress队列规定,并有可能被某些过滤器丢弃.即所谓策略.这些是很早就发生的(在进入内核更深 的部分之前).这样早地丢弃数据有利于节省CPU时间.数据包顺利通过的话,如果它是发往本地进程的,就会进入IP协议栈处理并提交给该进程.如果它需要 转发而不是进入本地进程,就会发往egress.本地进程也可以发送数据,交给Egress分类器.然后经过审查,并放入若干队列规定中的一个进行排队. 这个过程叫做"入队".在不进行任何配置的情况下,只有一个egress队列规定——pfifo_fast——总是接收数据包.数据包进入队列后,就等待 内核处理并通过某网卡发送.这个过程叫做"出队".这张图仅仅表示了机器上只有一块网卡的情况,图中的箭头不能代表所有情况.每块网卡都有它自己的 ingress和egress.
9.5. 分类的队列规定
CBQ(Class Based Queueing,基于类的队列)
一 旦数据包进入一个分类的队列规定,它就得被送到某一个类中——也就是需要分类.对数据包进行分类的工具是过滤器.一定要记住:"分类器"是从队列规定内部 调用的,而不是从别处.过滤器会返回一个决定,队列规定就根据这个决定把数据包送入相应的类进行排队.每个子类都可以再次使用它们的过滤器进行进一步的分 类.直到不需要进一步分类时,数据包才进入该类包含的队列规定排队.除了能够包含其它队列规定之外,绝大多数分类的队列规定都能够流量整形.这对于需要同 时进行调度(如使用SFQ)和流量控制的场合非常有用.如果你用一个高速网卡(比如以太网卡)连接一个低速设备(比如cable modem或者ADSL modem)
时,也可以应用.如果你仅仅使用SFQ,那什么用也没有.因为数据包进,出路由器时没有任何延迟.虽然你的输出网卡远远快于实际连接速率,但路由器中却没有队列可以调度.
9.5.2. 队列规定家族:根,句柄,兄弟和父辈
每 块网卡都有一个出口"根队列规定",缺省情况下是前面提到的pfifo_fast队列规定.每个队列规定都指定一个句柄,以便以后的配置语句能够引用这个 队列规定.除了出口队列规定之外,每块网卡还有一个入口,以便policies进入的数据流.队列规定的句柄有两个部分:一个主号码和一个次号码.习惯上 把根队列规定称
为"1:",等价于"1:0".队列规定的次号码永远是0.类的主号码必须与它们父辈的主号码一致.
9.5.2.1. 如何用过滤器进行分类
下图给出一个典型的分层关系:
根 1:
|
_1:1_
/ | /
/ | /
/ | /
10: 11: 12:
/ / / /
10:1 10:2 12:1 12:2
不要误解这张图!你千万不要想象内核处在树的顶点而下面部分是网络。数据包是在根队列规定处入队和出队的,而内核只同根打交道.一个数据包可能是按照下面这个链状流程进行分类的:
1: -> 1:1 -> 12: -> 12:2
数据包现在应该处于12:2下属的某个队列规定中的某个队列中。在这个例子中,树的每个节点都附带着一个过滤器,用来选择下一步进入哪个分支。这样比较直观。然而,这样也是允许的:
1: -> 12:2 也就是说,根所附带的一个过滤器要求把数据包直接交给12:2。
9.5.2.2. 数据包如何出队并交给硬件
当 内核决定把一个数据包发给网卡的时候,根队列规定1:会得到一个出队请求,然后把它传给1:1,然后依次传给10:,11:和12:,which each query their siblings,然后试图从它们中进行dequeue()操作.也就是说,内和需要遍历整颗树,因为只有12:2中才有这个数据包.换句话说,类及其兄 弟仅仅与其"父队列规定"进行交谈,而不会与网卡进行交谈.只有根队列规定才能由内核进行出队操作!更进一步,任何类的出队操作都不会比它们的父类更快. 这恰恰是你所需要的:我们可以把SFQ作为一个子类,放到一个可以进行流量整形的父类中,从而能够同时得到SFQ的调度功能和其父类的流量整形功能.
9.5.3. PRIO队列规定
PRIO 队列规定并不进行整形,它仅仅根据你配置的过滤器把流量进一步细分.你可以认为PRIO队列规定是pfifo_fast的一种衍生物,区别在每个频道都是 一个单独的类,而非简单的FIFO.当数据包进入PRIO队列规定后,将根据你给定的过滤器设置选择一个类.缺省情况下有三个类,这些类仅包含纯FIFO 队列规定而没有更多的内部结构.你可以把它们替换成你需要的任何队列规定.每当有一个数据包需要出队时,首先处理:1类.只有当标号更小的类中没有需要处 理的包时,才会标号大的类.当你希望不仅仅依靠包的TOS,而是想使用tc所提供的更强大的功能来进行数据包的优先权划分时,可以使用这个队列规定.它也 可以包含更多的队列规定,而pfifo_fast却只能包含简单的fifo队列规定.因为它不进行整形,所以使用时与SFQ有相同的考虑:要么确保这个网 卡的带宽确实已经占满,要么把它包含在一个能够整形的分类的队列规定的内部.后
者几乎涵盖了所有cable modems和DSL设备.严格地说,PRIO队列规定是一种Work-Conserving调度.
9.5.3.1. PRIO的参数与使用
tc识别下列参数:
bands
创建频道的数目.每个频道实际上就是一个类.如果你修改了这个数值,你必须同时修改:
priomap
如 果你不给tc提供任何过滤器,PRIO队列规定将参考TC_PRIO的优先级来决定如何给数据包入队.它的行为就像前面提到过的pfifo_fast队列 规定,关于细节参考前面章节.频道是类,缺省情况下命名为主标号:1到主标号:3.如果你的PRIO队列规定是12:,把数据包过滤到12:1将得到最高 优先级.
注意:0频道的次标号是1!1频道的次标号是2,以此类推.
9.5.3.2. 配置范例
我们想创建这个树:
root 1: prio
/ | /
1:1 1:2 1:3
| | |
10: 20: 30:
sfq tbf sfq
band 0 1 2
大批量数据使用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
# tc qdisc add dev eth0 parent 1:3 handle 30: sfq
现在,我们看看结果如何:
# tc -s qdisc ls dev eth0
qdisc sfq 30: quantum 1514b
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
qdisc sfq 10: quantum 1514b
Sent 132 bytes 2 pkts (dropped 0, overlimits 0)
qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 174 bytes 3 pkts (dropped 0, overlimits 0)
如你所见,0频道已经有了一些流量,运行这个命令之后发送了一个包!
现在我们来点大批量数据传输(使用能够正确设置TOS标记的工具):
# scp tc ahu@10.0.0.11:./
ahu@10.0.0.11's password:
tc 100% |*****************************| 353 KB 00:00
# tc -s qdisc ls dev eth0
qdisc sfq 30: quantum 1514b
Sent 384228 bytes 274 pkts (dropped 0, overlimits 0)
qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
Sent 2640 bytes 20 pkts (dropped 0, overlimits 0)
qdisc sfq 10: quantum 1514b
Sent 2230 bytes 31 pkts (dropped 0, overlimits 0)
qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 389140 bytes 326 pkts (dropped 0, overlimits 0)
如你所见,所有的流量都是经过30:处理的,优先权最低.现在我们验证一下交
互数据传输经过更高优先级的频道,我们生成一些交互数据传输:
# tc -s qdisc ls dev eth0
qdisc sfq 30: quantum 1514b
Sent 384228 bytes 274 pkts (dropped 0, overlimits 0)
qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
Sent 2640 bytes 20 pkts (dropped 0, overlimits 0)
qdisc sfq 10: quantum 1514b
Sent 14926 bytes 193 pkts (dropped 0, overlimits 0)
qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 401836 bytes 488 pkts (dropped 0, overlimits 0)
正常——所有额外的流量都是经10:这个更高优先级的队列规定处理的.与先前的整个scp不同,没有数据经过最低优先级的队列规定.
最后
以上就是闪闪小熊猫为你收集整理的linux流量控制(一)的全部内容,希望文章能够帮你解决linux流量控制(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复