7. 分类排队规则(分类 qdisc)

分类排队规则赋予了 Linux 流量控制系统极大灵活性。记住,分类排队规则允许与过滤器相关联,并将数据包分配到子分类和子排队规则上去。

root qdisc 或父类相关联的分类器有好几种不同的描述方法。与 root qdisc 相关联的分类可以叫做根分类,也可以叫做内部分类。任何不包含子分类的分类通常被称作叶子分类。在本文中,我们将使用类似树型结构的描述方法,同时也会使用类似家庭成员代词(如孙子节点、兄弟节点)进行描述。

7.1. HTB, 分层令牌桶

HTB 基于令牌和桶的概念,并按照基于对象的方法,同时配合 filter,实现了一个复杂而又精细的流量控制方法。利用其提供的 borrowing model 机制,用户能够构造出十分强大而有效的流量控制结构。HTB 最简单,同时也是最直接的使用,就是 shaping

如果已经充分了解了 tokensbuckets 的概念,或者是已经能够熟练使用 TBF,那么掌握 HTB 的使用方法也是水到渠成的事了。HTB 允许用户创建一系列具有不同参数的令牌桶,并按需要将这些令牌桶归类,同时配合使用 classifying,就能够实现较细粒度的流量控制。

下面是 tc 给出的 HTB 的用法。在编写 tcng 配置时,同样可以使用这些参数。

例 10. tc 中 HTB 的用法

用法: ... qdisc add ... htb [default N] [r2q N]
 default  当数据包没有被分类时,将通过这里指定的分类发送 {0}
 r2q      DRR quantums are computed as rate in Bps/r2q {10}
 debug    string of 16 numbers each 0-3 {0}

... class add ... htb rate R1 burst B1 [prio P] [slot S] [pslot PS]
                      [ceil R2] [cburst B2] [mtu MTU] [quantum Q]
 rate     rate allocated to this class (class can still borrow)
 burst    max bytes burst which can be accumulated during idle period {computed}
 ceil     指定分类的最高速率(不包含租借流量) {rate}
 cburst   burst but for ceil {computed}
 mtu      max packet size we create rate map for {1600}
 prio     叶子优先级,数字越小优先级越高 {0}
 quantum  叶子节点一次能够提供的字节数 {use r2q}

TC HTB version 3.3
      

7.1.1. 软件需求

和其他流量控制组件不一样,HTB 是一个较新的组件,你的内核可能不支持它。要让内核支持 HTB,必须使用 2.4.20 或更新版本的内核。就版本的内核需要打上补丁才能支持 HTB。要在用户空间上使用 HTB,请参考 HTB 中有关 iproute2tc 补丁的内容。

7.1.2. 整形

HTB 最常用的功能就是整形,也就是把出站速率限制在一个固定值之下。

所有的整形操作都在叶子分类上进行。内部分类和根分类都不会进行整形操作,它们仅在 borrowing model 中用于控制出借令牌应该如何分配。

7.1.3. 租借模型

HTB 的一个重要特性就是租借模型。当子分类的流量超过了 rate 时,它们就会向父分类借用令牌,直到子分类借到的令牌数量满足能让其达到 ceil 指定的速度为止,与此同时,它会暂缓发送数据包,直到有了足够多的令牌(token 或 ctoken)。由于 HTB 结构树中只有两种主要类型的节点(或者说是分类),下面以表格形式列出两种节点在不同情况下时会采取的动作。

表 2. HTB 中的节点在不同状态下的不同动作

节点类型节点状态HTB 内部状态动作
叶子节点< rateHTB_CAN_SEND 在令牌充足时叶子节点将会发送数据(不超过 burst 个数据包)
叶子节点> rate, < ceilHTB_MAY_BORROW 叶子节点会试图向父节点借用令牌(tokens 或 ctokens)。如果父节点有足够的令牌,就会一次性借给子节点 quantum 的整倍数个令牌,接着叶子节点发送最多 cburst 个字节。
叶子节点> ceilHTB_CANT_SEND 暂缓发送数据包,这将增大数据包延迟,使网络接口上的流量符合整形速率。
内部节点,根节点< rateHTB_CAN_SEND 本节点将会出借令牌给子节点。
内部节点,根节点> rate, < ceilHTB_MAY_BORROW 本节点试图将向父节点借用令牌(tokens 或 ctokens),并将借到的令牌按照 quantum 的整数倍出借给子节点。
内部节点,根节点> ceilHTB_CANT_SEND 本节点不会向父节点借用令牌,也不会向子节点出借令牌。

下图绘出了借用令牌和归还令牌的流向。为了使租借模型正常运行,必须为每个分类指定明确的令牌数量,及其子分类可用的令牌数量。同样,子分类或叶子节点必须向其父对象归还借用的令牌,层层向上直到根分类。

当子节点向其父节点借用令牌时,不论父节点是否已经超过了自己的 rate,他都会向上一级节点请求借用令牌,直到借到了令牌,或者达到了根节点为止。所以,出借令牌的流向是从根到叶子,而归还令牌的流向是从叶子到根。

此图中有多个 HTB 根分类,每一个根分类都可以模拟成一条虚电路。

7.1.4. HTB 分类参数

default

所有 HTB qdisc 对象的默认值,这个参数是可选的。默认的 default 值为0,这意味着所有通过 root qdisc 的数据包将以设备的最大吞吐能力发送出去。

rate

设定整形流量速率的最小速度。这个值可以当作承诺信息速率(CIR,也可以当作叶子节点的最低带宽。

ceil

设定整形流量速率的最大速度。租借系统的设置将影响这个参数的实际作用。这个参数可以当作是突发速率

burst

这是 rate 令牌桶的大小。 (参考 Tokens and buckets)。HTB 会在令牌(tokens)还没有到来的情况下提前发送 burst 个字节的数据。

cburst

这是 ceil 令牌桶的大小。HTB 会在令牌(ctokens)还没有到来的情况下提前发送 burst 个字节的数据。

quantum

这个参数在 HTB 的租借系统中很重要。通常,HTB 会自己计算合适的 quantum 值,而不需要用户手工指定。有人认为调整这个参数能在出借令牌和整形方面收到不少好处,但也有不少人持反对意见,because it is used both to split traffic between children classes over rate (but below ceil) and to transmit packets from these same classes.

r2q

r2q 可以由用户自行指定,HTB 会参考用户设定的值,为每个分类计算出一个更合适的 quantum

mtu

prio

7.1.5. Rules

下面是一些一般性的提示,这些提示是从 http://docum.org/LARTC mailing list 中选取出来的,可以给入门用户提供指导性的意见,尽可能地发挥 HTB 的效能。对于高级用户,则可以根据自己的实际需要调整 HTB 以获取最大效益。

  • 在 HTB 中,只有叶子节点才会对流量进行整形。参考 第 7.1.2 节 “整形”

  • 因为在 HTB 只有叶子节点会对流量进行整形,所以一个分类下的所有叶子节点的 rate 之和不应该超过这个分类的 ceil。通常我们建议将分类的 rate 值设定为其所有子节点的 rate 之和,这样,分类随时都能有剩余的带宽(ceil - rate)分配给子节点。

    由于这个概念十分重要,所以才一而再再而三地强调:在 HTB 中只有叶子节点才会对流量进行整形,数据包只会在叶子节点中被暂存,任何中间节点都不会对流量进行整形,中间节点只在租借模型中起作用(参考 第 7.1.3 节 “租借模型”)。

  • quantum 仅在当一个节点的速率大于 rate 而小于 ceil 时起作用。

  • quantum 的值应该至少设为和 MTU 一样大,或者比 MUT 更大。即使 quantum 设置值过小,但一有机会 HTB 就会立即发送一个数据包,这将导致 HTB 无法正确计算带宽消耗,也就无法正确地对流量进行整形 [9]

  • 父节点每次借给子节点的令牌数都是 quantum 的整数倍,因此,为了使网络反应更加迅速、粒度更细,quantum 应该设置得尽可能小,而又不能小于 MTU。

  • tokens 和 ctokens 仅仅在叶子节点上才有区别,因为非叶子节点只会将令牌借给它自己的子节点。

  • HTB 的租用模型更精确的说法应该叫做租借后使用机制

7.2. HFSC, 分层公平服务曲线

HFSC(Hierarchical Fair Service Curve,HFSC)能够将延迟敏感型流量和吞吐量敏感型流量区分对待,它会根据服务曲线定义在拥挤的线路上保证延迟敏感型数据包能够被及时发送,同时线路又保持有较大的吞吐量。有关 HFSC 的详细情况请参考 HFSC Scheduling with LinuxA Hierarchical Fair Service Curve Algorithm For Link-Sharing, Real-Time and Priority Services

本节尚待日后完成。

7.3. PRIO, 优先级调度

PRIO 分类排队规则十分简单,当允许发送数据包时,PRIO 会首先检查第一个分类中有没有数据包,如果有就发送出去,如果没有数据包,就检查下一个分类,以此类推,直到检查完所有的分类。

本节尚待日后完成。

7.4. CBQ, 基于类的队列

基于类的队列(Class Based Queuing)是非常经典的排队算法。本节尚待日后完成。



[9] HTB 会使用 quantum 而非实际的数据包大小来计算流量,这就会导致流量消耗计算错误,且误差会迅速扩大。