HTB介绍

HTB(Hierarchical Token Bucket)是一种分类排队方法,对于处理不同种类的流量很有帮助。 本文将集中讨论 分层令牌桶 (HTB)的 "Token Bucket "部分-单队列内部的算法和配置实例。

Token Bucket算法(图中红色部分)

Token Bucket算法是对一个桶的类比,在这个桶里,以字节为单位的特定速率被添加到令牌。桶本身有一个特定的容量。

如果桶满了,新到的令牌就会被丢弃。

桶的容量=桶的大小*最大限制

  • bucket size (0..10, Default:0.1) - 队列选项在RouterOS v6.35中添加,在此之前,它被硬编码为一个 "0.1 "的值。

在允许任何数据包通过队列之前,队列桶会被检查,看它是否已经包含了足够的令牌。

如果是,适当数量的令牌被移除("兑现"),数据包允许通过队列。

如果不是,数据包就停留在数据包等待队列的起点,直到有了适当数量的令牌。

在多级队列结构的情况下,在子队列中使用的令牌也被 "收取"到父队列中。换句话说,子队列从父队列中 "借用 "令牌。

数据包队列(图中蓝色部分)

数据包队列的大小、顺序、数据包如何添加到这个队列,以及数据包何时丢弃是由以下因素决定的:

令牌速率选择(图中黑色部分)

任何时候的最大令牌速率都等于这些数值中最高的活动项。

  • limit-at (NUMBER/NUMBER):保证上传/下载到目标的速率

  • max-limit (NUMBER/NUMBER):允许目标的最大上传/下载速率。

  • burst-limit (NUMBER/NUMBER):当 "burst "激活时,允许目标的最大上传/下载速率。

burst-limit 只有在 'burst' 处于允许状态时才有效-更多信息在这里。Queue Burst

limit-at 为最高值的情况下,要发出额外的令牌来补偿所有未从父队列中借入的缺失令牌。

图示

Bucket Size动作

一个简单的设置,所有来自一个IP地址的流量都被标记为数据包标记:

/ip firewall mangle

add chain =forward action =mark-connection connection-mark =no-mark src-address =192.168.88.101 new-connection-mark =pc1_conn

add chain =forward action =mark-connection connection-mark =no-mark dst-address =192.168.88.101 new-connection-mark =pc1_conn

add chain =forward action =mark-packet connection-mark =pc1_conn new-packet-mark =pc1_traffic

默认队列桶

/queue tree

add name =download parent =Local packet-mark =PC1-traffic max-limit =10M

add name =upload parent =Public packet-mark =PC1-traffic max-limit =10M

在此,bucket-size=0.1,所以bucket-capacity= 0.1 x 10M = 1M

如果bucket满了(也就是客户端在一段时间内没有使用队列的全部容量),接下来的1Mb流量可以不受限制的速度通过队列。

大队列桶

/queue tree

add name =download parent =Local packet-mark =PC1-traffic max-limit =10M bucket-size =10

add name =upload parent =Public packet-mark =PC1-traffic max-limit =10M bucket-size =10

尝试把同样的逻辑用于桶为最大值时的情况。

这里,bucket-size=10,所以bucket-capacity= 10 x 10M = 100M

如果桶已经满了(也就是客户端在一段时间内没有使用队列的全部容量),则接下来的100Mb流量可以不受限制地通过队列。

所以有:

  • 20Mbps的传输速度为10s

  • 60Mbps的传输突发时间为2s

  • 1Gbps传输突发速率约100ms

可以看到,该桶允许通过队列的流量有一种 "突发性"。该行为类似正常的突发功能,但缺少突发上限。如果我们在队列结构中利用桶的大小,就可以避免这种挫折。

大的子队列桶,小的父队列桶

/queue tree

add name =download_parent parent =Local max-limit =20M

add name =download parent =download_parent packet-mark =PC1-traffic max-limit =10M bucket-size =10

add name =upload_parent parent =Public max-limit =20M

add name =upload parent =upload_parent packet-mark =PC1-traffic max-limit =10M bucket-size =10

在此:

  • parent queue bucket-size=0.1, bucket-capacity= 0.1 x 20M = 2M

  • child queue bucket-size=10, bucket-capacity= 10 x 10M = 100M

父队列比子队列更快地耗尽令牌,由于子队列总是从父队列中借用令牌,整个系统被限制在父队列的令牌速率上-因此,最大限制=20M。这一速率将持续到子队列用完令牌,并被限制在10Mbps的令牌速率。

通过这种方式,可以在20Mbps的速度下进行突发,时间长达10秒。

配置

必须遵循三个基本步骤来创建HTB:

  • 匹配和标记流量 - 对流量进行分类,以便进一步使用。由一个或多个匹配参数组成,为特定类别选择数据包。

  • 创建规则(策略)来标记流量 - 将特定的流量类别放入特定的队列,并定义对每个类别采取的行动。

  • 为特定接口附加策略** - 为所有接口(全局输入、全局输出或全局总数)、特定接口或特定父队列附加策略。

HTB允许创建一个分层的队列结构,并确定队列之间的关系,如 "父-子 "或 "子-子"。

只要队列至少有一个孩子,它就成为一个 内部 队列,所有没有孩子的队列是 叶子 队列。叶子 队列进行实际的流量消耗,内部 队列只负责流量分配。所有的 叶子 队列都被平等对待。

在RouterOS中,有必要指定 父母 选项,把一个队列作为另一个队列的子队列。

双重限制

HTB中的每个队列有两个速率限制。

  • CIR (Committed Information Rate) - (RouterOS中的 limit-at )最坏情况,无论如何都会得到这个流量(假设真的可以发送这么多数据)。

  • MIR (Maximal Information Rate) - (RouterOS中的 max-limit) 最好的情况是,如果队列的上级有多余的带宽,流量可以达到的速率。

换句话说,一开始所有队列的 limit-at**(**CIR)将得到满足,然后子队列才会尝试从父队列中借用必要的数据速率,以达到其**max-limit**(MIR)。

无论怎样,CIR 将被分配给相应的队列。(即使超过了父代的最大限制)

这就是为什么,为了确保双重限制功能的最佳(按照设计)使用,我们建议坚持这些规则。

  • 所有子女的承诺速率之和必须小于或等于父母的可用流量。

CIR(parent)* ≥ CIR(child1) +…+ CIR(childN)*在父母是主要父母的情况下,CIR(parent)=MIR(parent)

  • 任何子队列的最大速率必须小于或等于父母的最大速率

MIR (parent) ≥ MIR(child1) & MIR (parent) ≥ MIR(child2) & … & MIR (parent) ≥ MIR(childN)

Winbox中的队列颜色:

  • 0% - 50%可用流量 - 绿色

  • 51% - 75%可用流量 - 黄色

  • 76% - 100%可用流量 - 红色

优先权

无论如何,所有队列的 limit-at**(**CIR)都会被送出。

优先级负责将剩余的父队列流量分配给子队列,以便它们能够达到 max-limit

优先级较高的队列将在优先级较低的队列之前达到其 最大限度。8是最低的优先级,而1是最高的。

请注意,优先级只起作用。

  • 对于 叶子 队列-内部 队列的优先级没有意义。

  • 如果指定了 max-limit (不是0)

示例

本节中将分析HTB的运行情况。为了做到这一点,将采用一个HTB结构,并试图涵盖所有可能的情况和功能,通过改变HTB必须回收的传入流量的数量改变一些选项。

结构

HTB结构由5个队列组成。

  • Queue01 内部队列有两个子队列 - Queue02Queue03

  • Queue02 内部队列有两个子队列 - Queue04Queue05

  • Queue03 叶子队列

  • Queue04 叶子队列

  • Queue05 叶子队列

Queue03Queue04、Queue05 是需要10Mbps的客户端,出站接口能够处理10Mbps的流量。

Example 1: Usual case

  • Queue01 limit-at=0Mbps max-limit=10Mbps

  • Queue02 limit-at=4Mbps max-limit=10Mbps

  • Queue03 limit-at=6Mbps max-limit=10Mbps priority=1

  • Queue04 limit-at=2Mbps max-limit=10Mbps priority=3

  • Queue05 limit-at=2Mbps max-limit=10Mbps priority=5

例1的结果

  • Queen03 将收到6Mbps

  • Queue04 将收到2Mbps的数据

  • Queue05 将收到2Mbps。

  • 说明: HTB的构建方式是,通过满足所有的 limit-at,主队列不再有吞吐量可以分配。

例2:通常情况下的最大限制

  • Queue01 limit-at=0Mbps max-limit=10Mbps

  • Queue02 limit-at=4Mbps max-limit=10Mbps

  • Queue03 limit-at=2Mbps max-limit=10Mbps priority=3

  • Queue04 limit-at=2Mbps max-limit=10Mbps priority=1

  • Queue05 limit-at=2Mbps max-limit=10Mbps priority=5

例2的结果

  • Queue03 将收到2Mbps的数据

  • Queue04 将收到6Mbps的数据

  • Queue05 将收到2Mbps的数据

  • 说明: 在满足所有 limit-at 后,HTB将把吞吐量给有最高优先级的队列。

例3:内部队列limit-at

  • Queue01 limit-at=0Mbps max-limit=10Mbps

  • Queue02 limit-at=8Mbps max-limit=10Mbps

  • Queue03 limit-at=2Mbps max-limit=10Mbps priority=1

  • Queue04 limit-at=2Mbps max-limit=10Mbps priority=3

  • Queue05 limit-at=2Mbps max-limit=10Mbps priority=5

例3的结果

  • Queue03 将收到2Mbps的数据

  • Queue04 将收到6Mbps的数据

  • Queue05 将收到2Mbps的数据

  • 说明: 在满足所有的 limit-at 后,HTB将把吞吐量给具有最高优先级的队列。因此,内部 队列 Queue02 指定了 limit-at,通过这样做,它为队列 Queue04Queue05 保留8Mbps的吞吐量。在这两个队列中,Queue04 的优先级最高,这就是为什么它能获得额外的吞吐量。

例4:叶子队列limit-at

  • Queue01 limit-at=0Mbps max-limit=10Mbps

  • Queue02 limit-at=4Mbps max-limit=10Mbps

  • Queue03 limit-at=6Mbps max-limit=10Mbps priority=1

  • Queue04 limit-at=2Mbps max-limit=10Mbps priority=3

  • Queue05 limit-at=12Mbps max-limit=15Mbps priority=5

例4的结果

  • Queue03 将收到~3Mbps的数据

  • Queue04 将收到~1Mbps的数据

  • Queue05 将收到~6Mbps的数据

  • 说明: 只有满足所有的 limit-at,HTB才被迫分配20Mbps-6Mbps到 Queen03,2Mbps到 Queen04,12Mbps到 Queen05,但输出接口能够处理10Mbps。由于输出接口队列通常是先进先出的,吞吐量分配将保持6:2:12或3:1:6的比例。