背景

  • 为什么要限速?

限速的目的是防止有人恶意占用带宽,在保证用户正常业务前提下,保证整个网络不发生拥塞,提升整个网络的服务质量。

  • 限速的方式?

在高并发的场景下,我们的优化和保护系统的方式通常有:多级缓存、资源隔离、熔断降级、限流等等。

网络限速有很多种方式,比如网卡(接口)限速,队列限速,meter表限速。其中meter表限速是颇具代表性的限速方式。

流量限速技术

常用的流量限速有两种技术:

限速之令牌桶理解_丢包

流量监管TP(Traffic Policing)

可以监督不同流量进入网络的速率,对超出部分的流量进行“惩罚”,使进入的流量被限制在一个合理的范围之内,从而保护整个网络资源和用户的利益。

流量整形(Traffic Shaping)

背景

对于网络传输而言,丢包带来的成本是很高的,因为一些重要的数据包丢失后,是需要 “重传” 的,而 “重传” 太多,来回反复会增加了数据传输的延时,也会进一步恶化网络负荷,最终极大地降低了传输的效率。

需要从根本上尽可能地减少 “丢包” 的产生,简单来说,就是控制单位时间内送入网络传输的数据量,尽量平滑且不要超过网络带宽承载能力。

为了避免丢包,我们需要尽可能地将数据 “平滑” 地送入网络中,因此,“流量整形” 在此派上了用场,它作用于 “发送模块”,目标是调整数据传输的平均速率,防止突发性的流量暴增导致网络拥塞和丢包。

定义

流量整形通常是为了使报文速率与下游设备相匹配。当从高速链路向低速链路传输数 据或发生突发流量时,带宽会在低速链路出口处出现瓶颈,导致数据丢失严重。这种 情况下,需要在进入低速链路的设备出口处进行流量整形;所以流量整形是一种主动调整流量输出速率的措施,其作用是限制流量与突发,使这类报文以比较均匀的速率向外发送。

流量整形是用于限制某个或某些队列的输出速率,超速的报文不是直接丢弃,而是暂时存在缓存里,等空闲了还是会输出,只有缓存满了之后才会丢弃。流量整形将上游不规整的流量进行削峰填谷,使流量输出比较平稳,从而解决下游设备的拥塞问题。

流量整形处理流程图

单速单桶技术的基于流的队列整形;流量整形通常使用缓冲区和令牌桶来完成:

限速之令牌桶理解_ci_02

具体处理流程如下:

  1. 当报文到来的时候,首先对报文进行分类,使报文进入不同的队列。
  2. 若报文进入的队列没有配置队列整形功能,则直接发送该队列的报文;否则,进入下一步处理。
  3. 按用户设定的队列整形速率向令牌桶中放置令牌:
  • 如果令牌桶中有足够的令牌可以用来发送报文,则报文直接被发送,在报文被发送的同时,令牌做相应的减少。
  • 如果令牌桶中没有足够的令牌,则将报文放入缓存队列,如果报文放入缓存队列时,缓存队列已满,则丢弃报文。
  1. 缓存队列中有报文的时候,会与令牌桶中的令牌数作比较,如果令牌数足够发送报文则转发报文,直到缓存队列中的报文全部发送完毕为止。

使用流量整形的效果

通过在上游设备的接口出方向配置流量整形,将上游不规整的流量进行削峰填谷, 输出一条比较平整的流量(如图 2-23),从而解决下游设备的瞬时拥塞问题。

限速之令牌桶理解_丢包_03

流量监管和流量整形的对比

限速之令牌桶理解_限流_04

 

对于流量监管技术,当流量速率达到所配置的最大速率时,将丢弃(或重新标记)超额流量。其结果是,输出速率显示为带有波峰和波谷的锯齿状。相对于比较重要的突发流量,如果采用令牌桶技术可能导致重要数据的丢失;

采用流量整形技术,将超出的流量来不及转发的数据存放起来,在端口有带宽时再转发。流量整形在队列中保留额外的数据包,然后对额外的数据包进行调度,以便随时间的增加稍后传输。流量整形的结果是一个平滑的数据包输出速率。

限速之令牌桶理解_ci_05

 

常见的限流算法

既然要限速,那首先要解决测量速度的问题。以下介绍测试方法。

QoS是网络中提供差异化服务的重要方法,它通过区分不同的流量和优先级,为不同的应用和使用者提供不同质量的网络服务,比如,金融网络,可能购买了专线,要求延迟小,更不能忍受丢包,自然优先级就高些;又比如网络直播和游戏,对于网络的延迟要求非常高,而普通的上网用户则没有这么高的要求;

计数器算法

计数器算法简单粗暴,设置 1s 内的请求数阈值 qps。比如 qps = 100,从第一个请求进来开始计时,并将计数值置 0,在接下来的1s 内,每来一个请求,就把计数值加 1,如果计数值达到100,那后面的请求就全部拒绝。等到 1s 结束,把计数恢复为 0,重新开始计数。

缺点:

如果在某个 1s 内的前 10ms,已经通过了100个请求,那后面的 990ms,就只能眼巴巴的把请求拒绝。这种现象被称为突刺现象

漏桶算法

限速之令牌桶理解_ci_06

为了消除突刺现象,可以设置一个漏桶(漏斗)。漏桶算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出;

请求进来,相当于水倒入漏桶,然后从下面小口缓慢匀速的流出,不管上面的流量多大,下面流量始终不变。

所以我们需要设置两个参数:桶最大容量 cap 和漏出速率 r。若当前进来的请求数达到 cap,即漏桶满了,那后面进来的请求就拒绝掉;若 r = 50,则表示每秒处理 50 个请求,即 20ms 处理一个请求。

实现的话,可以用队列作为漏桶,然后拿另外一个线程以速率 r 从队列中拿请求来处理。一次可以拿多个请求实现并发。

缺点

无法应对短时间的突发流量。漏桶算法的出水速度是恒定的,那么意味着如果瞬时大流量的话,将有大部分请求被丢弃掉(也就是所谓的溢出)。

令牌桶算法生成令牌的速度是恒定的,而请求去拿令牌是没有速度限制的。这意味,面对瞬时大流量,该算法可以在短时间内请求拿到大量令牌,而且拿令牌的过程并不是消耗很大的事情。

令牌桶算法

令牌桶算法中想象了一种令牌令牌桶。令牌桶容量为 b,令牌以速率 r 产生,比如 r = 2 表示每秒产生 2 个令牌,即每 500ms 产生一个。当大量请求进来时,每个请求会消耗一个令牌,当令牌被消耗时,让后面的请求处于等待状态或直接将其拒绝掉。是不是很简单?实现的话,不需要实现令牌,也不需要实现令牌桶,只需要有一个变量记录令牌数,当请求进来时,判断令牌数是否为零,来决定处理还是拒绝,若处理的话要让令牌数 -1。另外需要一个线程来只要令牌数小于 b 就以 r 的速率让令牌数 +1。

 

定义

令牌桶(Token-Bucket)是目前最常采用的一种流量测量方法,用来评估流量速率是否超过了规定值。这里的令牌桶是指网络设备的内部存储池,而令牌则是指以给定速率填充令牌桶的虚拟信息包。

令牌桶可以看作是一个存放令牌的容器,预先设定一定的容量。

系统按设定的速度向桶中放置令牌,当桶中令牌满时,多余的令牌溢出。

限速之令牌桶理解_丢包_07

限速之令牌桶理解_限流_08

限速之令牌桶理解_ci_09

说明:

令牌桶只是一种流量测量方法,并不能对流量进行过滤或采取某种措施,比如说丢弃数据包等,这些操作由其他功能完成。

令牌桶中装的是令牌而不是分组。

如上所示,匀速的产生令牌,往桶里面丢;每次请求来,看是否有多余的令牌。如果有,获取令牌执行正常业务;如没有,丢包限速。

令牌桶算法测速限速的原理就是:每个符合规则的报文,只有在从桶中拿到令牌后才能发送出去。拿不到令牌,则丢弃;

1)桶中的令牌是怎么来的呢?

可以自己设置桶中令牌生成的速度,也就是通过设置生成令牌的生成速度来定义发送数据包的速度。

分类

通常为了解决数据包突发性问题等,会使用2个令牌桶,根据他们各自生成令牌的速度,分为单速三色标记和双速三色标记。

RFC 中定义了两种令牌桶算法:

单速率三色标记(single rate three color marker,srTCM,RFC2697定义,或称为单速双桶算法)算法,主要关注报文尺寸的突发。
双速率三色标记(two rate three color marker,trTCM,RFC2698定义,或称为双速双桶算法)算法,主要关注速率的突发。

两种算法的评估结果都是为报文打上红、黄、绿三种颜色的标记,所以称为“三色标记”。这两种算法都允许流量在一定程度上突发,但单速率三色标记关注报文尺寸的突发,而双速率三色标记则关注速率上的突发。单速率较双速率实现简单,成为目前业界比较常用的流量评估方式。

QoS 会根据报文的颜色,设置报文的丢弃优先级;两种算法都可以工作于色盲模式和色敏模式下。

原理

基本原理

令牌桶算法,顾名思义,系统按照一定的投放方式向桶中放置令牌,当桶中令牌满时,多出的令牌溢出,桶中令牌不再增加。如下图所示。

当有需要限速的数据包通过的时候,依据数据报文的长度算出需要取走的令牌数N(比如 限速的bps值和桶中的令牌数N对应)。

如果桶中的令牌数量大于N,那么此数据包就顺利过了限速测试。

反之,此数据包就没有通过限速测试,于是就将报文进行丢弃处理(大多数情况下是如此,也可以进行其他处理,依赖用户程序的设计)。

限速之令牌桶理解_丢包_10

桶中令牌的投放方式

系统按照一定的投放方式向桶中放置令牌,当桶中令牌满时,多出的令牌溢出,桶中令牌不再增加。存在2种投放方式去投放桶中令牌:

1)方式一:设置定时器,在定时器的回调函数中周期性的放入令牌。

周期性的添加,定时器的时间间隔就是令牌桶的容量与添加速率的比值:△t=CBS/CIR,每次添加的令牌数为 CBS 个。

解析: 可以利用dpdk的定时器,比如设置每1秒,call以下回调函数,放入令牌1 * N个令牌。

缺陷1: 如果在这一秒钟内,如果前0.5秒的突发流量将令牌都消耗完了,那么后0.5秒的报文不就全部丢掉了。有人说,可以将这个间隔设置小一点啊,比如每1/1000秒放入N/1000个令牌。但是问题在于,这个间隔到底是多少好呢?

比如,粒度细化到 每隔 1s/CIR 时间添加一个令牌;(1s可以转化为 cycles,即每个n个cycles往令牌桶中添加一个令牌;)

缺陷2: 无法处理突发流量,原因见方式3。

注:其实也没有必要单独搞一个真的定时器,或者一个单独的线程进行投放令牌;只需要在每次数据包过桶前,判断下当前时间和上次投放桶令牌时间的差值diff_cycles 是否满足 period_cycles 即可,来决定是否投放令牌;

2)方式2: 按时间间隔放入

一次性添加,添加令牌的数量是△t×CIR(△t 是当前时间与上次添加令牌的时间之差),且是一次添加完毕,并不是按照一定速率添加。

解析: 按时间间隔放入,假设当前报文和上一个报文的时间间隔为1ms秒,那么放入1/1000 * N 个令牌。这种方式的好处在于针对于每个数据包的处理前都会放入令牌,分散令牌的放入。

缺陷: 无法处理突发流量,原因见方式3

限速之令牌桶理解_限流_11

初始化桶内的令牌数为N,限速为 rate Bps, 即对应关系为 N1:rate1 = N2: rate2;

一个数据包,包长为 len:则 N1:rate1 = N2: len, 所以 N2 = len * (N1/rate1)

3) 方式2改进

背景: 方式1和方式2都面临一个问题,如果有突发流量,那么可能在极短的时间内消耗全部的令牌;前期短期内大量的流量被放行,从而对系统造成威胁;后续的时间内,集中丢包。

解析: 当出现丢包后,那么在接下来的200us内的前64个报文都会被丢弃(即200us内丢弃的是64个包,而不是大量的包)。对于200us和64这个值都是经验值,可以在真实场景中进行调优。

缺陷: 这个方式降低了突发流量对系统的威胁,但是会对限速的准确性有一定的影响,通过测试可以证明。

限速之令牌桶理解_限流_12

注:方式2和方式3可以协作运行,比如用方式3先进行防攻击限速,然后再用方式2进行精确限速。

CAR

什么是CAR

流量监管采用承诺访问速率CAR(Committed Access Rate)来对流量进行控制。CAR利用令牌桶来衡量每个数据报文是超过还是遵守所规定的报文速率。

CAR主要有两个功能:

  • 流量速率限制:通过使用令牌桶对流经端口的报文进行度量,使得在特定时间内只有得到令牌的流量通过,从而实现限速功能。
  • 流分类:通过令牌桶算法对流量进行测量,根据测量结果给报文打上不同的流分类内部标记(包括服务等级与丢弃优先级)。

 

CAR的处理流程

限速之令牌桶理解_丢包_13

  • 当报文到来时,首先检查端口的匹配规则,如果匹配上了,则进行速率控制,报文进入令牌桶中进行流量速率评估。
  • 令牌桶评估后,报文被标记为红、黄、绿三种颜色。红色表示报文速率过大,不符合规定;黄色表示虽然不符合规定但允许临时的突发,绿色表示符合规定。
  • 报文标为红色的直接丢弃,黄色则重新标记后转发,绿色则直接转发。

 

CAR的报文标记过程

CAR中令牌添加方式是报文触发,添加令牌的数量是CIR×当前时间与上次添加令牌的时间之差。向桶内注入令牌后,再判断桶内的令牌数是否满足传送该报文的要求。

CAR支持单速单桶、单速双桶、双速双桶的标记方式。

单速率三色标记(srTCM单速双桶算法) 算法

定义

单速双桶采用RFC2697定义的单速三色标记器srTCM(Single Rate Three Color Marker)算法对流量进行测评,根据评估结果为报文打颜色标记,即绿色、黄色和红色。

限速之令牌桶理解_限流_14


如上图所示,为方便描述将两个令牌桶称为C桶和E桶(意为Excess超额桶),用Tc和Te表示桶中的令牌数量

CIR(Committed Information Rate):承诺信息速率,单位是 bit/s,表示向C桶中投放令牌的速率;

CBS(Committed Burst Size):承诺突发尺寸,单位是 bit,即为令牌桶的容量(深度),即C桶瞬间能够通过的承诺突发流量,用来定义在部分流量速率超 过CIR之前的最大突发流量;承诺突发尺寸必须大于报文的最大长度(最大时一个分组可以领取桶中的全部令牌)。CBS越大,表示所允许的突发量越大。

EBS(Excess Burst Size):超额突发尺寸,表示E桶的容量,即E桶瞬间能够通过的超出突发流量,用来定义在所有流量速率超过CIR之前的 最大突发量;

B: 对于到达的报文,用B表示报文的大小:

C 桶容量为CBS, E 桶容量为EBS,总容量是CBS+EBS。如果不允许有突发流量,EBS 则设置成 0。

当 EBS≠0 时,称为单速双桶。

当 EBS=0,E桶的令牌数始终为 0,相当于只使用了一个令牌桶——C桶,这种情况也称为单速单桶。

向桶中投放令牌

限速之令牌桶理解_ci_15

单速双桶令牌添加方式比较简单,先以CIR的速率往C桶中添加令牌,当C桶容 量到达 CBS 后(C桶满了),再以相同的速率往E 桶中添加令牌(E 桶的令牌用做 以后临时超过CIR的突发流量),当E桶容量到达 EBS 后(E 桶也满了),则新产 生的令牌将会被丢弃。 初始状态下,C 桶和 E桶都是满的。

系统按照CIR速率向桶中投放令牌:

若Tc<CBS,Tc增加;

若Tc=CBS,Te<EBS,Te增加;

若Tc=CBS,Te=EBS,则都不增加。

流量评估规则(数据包过桶)

用B表示到达的报文的大小:用 Tc 和 Te 表示桶中的令牌数量,Tc 和 Te 初始化等于CBS 和EBS

当报文到来后,直接与桶中的令牌数相比较,如果有足够的令牌就转发(通常用一个令牌关联一个比特的转发权限),如果没有足够的令牌则丢弃或缓存。 

若B≤Tc,报文被标记为绿色,且Tc减少B;

若Tc<B≤Te,报文被标记为黄色,且Te减少B;

若Te<B,报文被标记为红色,且Tc和Te都不减少。

所以,单速双桶模式允许突发流量尺寸

当用户的流量速率小于配置的CIR时,报文被标记为绿色;

当用户的突发流量大小大于配置的CBS而小于EBS时,报文被标记为黄色;

当用户的突发流量大小大于配置的EBS时,报文被标记为红色。

注:可以根据红绿灯的,绿色表示通行,黄色表示警告,红色为禁止通行;

色盲模式

色盲模式,即不关注报文之前的颜色;

在对到达报文(假设报文大小为B)进行评估时,遵循以下规则:

  • 对于单速单桶(EBS=0):
  • 如果报文长度不超过 C桶中的令牌数 Tc,则报文被标记为绿色,且 Tc=Tc-B;
  • 如果报文长度超过C 桶中的令牌数 Tc,报文被标记为红色,Tc 值不变。
  • 对于单速双桶(EBS≠0):
  • 如果报文长度不超过 C桶中的令牌数 Tc,则报文被标记为绿色,且 Tc=Tc-B;
  • 如果报文长度超过C 桶中的令牌数 Tc 但不超过E 桶中的令牌数 Te,则报文被 标记为黄色,且 Te=Te-B;

如果报文长度超过E 桶中的令牌数 Te,报文被标记为红色,但 Tc 和 Te 不变。

色敏模式

色敏模式,即关注报文之前的颜色;

  • 对于单速单桶(EBS=0):
  • 如果报文已被标记为绿色但报文长度不超过C 桶中的令牌数 Tc,则报文被标记为绿色,且 Tc=Tc-B;
  • 如果报文已被标记为绿色且报文长度超过 C桶中的令牌数 Tc,则报文被标记为红色,Tc 保持不变;
  • 如果报文已被标记为黄色或红色,都直接将报文标记为红色,Tc 保持不变;
  • 对于单速双桶(EBS≠0):
  • 如果报文已被标记为绿色且报文长度不超过C桶中的令牌数 Tc,则报文被标记为绿色,且 Tc=Tc-B;
  • 如果报文已被标记为绿色且报文长度超过C桶中的令牌数Tc但不超过E桶中的令牌数Te,则报文被标记为黄色,且 Te=Te-B;
  • 如果报文已被标记为黄色但报文长度不超过E桶中的令牌数 Te,则报文被标记为黄色,且 Te=Te-B;
  • 如果报文已被标记为黄色且报文长度超过E桶中的令牌数 Te,则报文被标记为红色,且Te保持不变;
  • 如果报文已被标记为红色,直接将报文标记为红色,Tc 和Te不变。

借贷机制

无借贷模式

过桶的时候,使用的是比较tc >= pkt_len,没有实现借贷,可能会导致报文不平滑,举个例子:

  • 假设设备端口的CIR设置为1Mbps,CBS为2000bytes, EBS为2000bytes,初始状态时C桶和E桶满。
  • 假设第1个到达的报文是1500 bytes 时,检查C桶发现令牌数大于数据包的长度,所以数据包被标为绿色,C桶减少1500 bytes,还剩500 bytes,E桶保持不变。
  • 假设1ms之后到达第2个报文1500 bytes,新增令牌 CIR*1ms=1000bit=125bytes,此时C桶共有625 bytes,令牌不够。检查E桶有足够令牌,因此报文标记为黄色,E桶减少1500bytes,剩 500bytes,C桶不变。
  • 假设又过1ms后到达第3个报文1000 bytes,新增令牌 CIR*1ms=1000bit=125bytes,此时C桶共有750bytes,令牌不够,检查E桶也不够,因此报文被标记为红色, C桶、 E桶令牌数不变。
  • 假设又过20ms后到达第4个报文1500bytes,新增令牌CIR*20ms=20000bit=2500bytes,C桶此时令牌数3250 bytes,CBS=2000bytes,因此溢出1250bytes 添加到E桶,此时E桶有1750bytes。由于此时C桶大于报文长度,报文标记为绿色,C桶减少1500bytes剩500bytes,E桶不变。

整个过程如下表所示:

限速之令牌桶理解_限流_16

 

借贷模式

当报文到来后,只要令牌桶中有令牌,无论数量是否足够,都可以转发报文。当令牌数量小于报文长度时,就可以欠债转发,即转发后令牌桶中令牌数目为负;当下次添加令牌的时候,先还清所欠债务,再继续转发报文。这种处理方法较前者在处理突发报文时有优势,能够保证报文发送的连续性。

如果使用了借贷后,计算颜色的过程变成:

IF tc > 0

Color = GREE;

Tc -= Pkt_len;

ELSE IF te > 0

Color = YELLOW;

Te -= Pkt_len;

ELSE

Color = RED;

上面的过程变成:

限速之令牌桶理解_丢包_17

20ms这个上对于上面的过程,tc没有溢出1250bytes的令牌,整个报文输出表现的更为平滑。

 

范例

假设设备端口的CIR设置为1Mbps,CBS为2000 bytes,EBS为2000 bytes,初始状态时C桶和E桶满。

  • 假设第1个到达的报文是1500 bytes时,检查C桶发现令牌数大于数据包的长度,所以数据包被标为绿色,C桶减少1500 bytes,还剩500 bytes,E桶保持不变。
  • 假设1ms之后到达第2个报文1500 bytes,但C桶只有500 bytes,小于报文长度,因此新增令牌CIR*1ms=1000bit=125bytes,此时C桶共有625 bytes,依然不够。检查E桶有足够令牌,因此报文标记为黄色,E桶减少1500bytes,剩500bytes,C桶不变。
  • 假设又过1ms后到达第3个报文1000 bytes,但C桶只有625 bytes,小于报文长度,因此新增令牌CIR*1ms=1000bit=125bytes,此时C桶共有750 bytes,依然不够,检查E桶也不够,因此报文被标记为红色,C桶、E桶令牌数不变。
  • 假设又过20ms后到达第4个报文1500 bytes,但C桶只有750 bytes,小于报文长度,因此C桶新增令牌CIR*20ms=20000bit=2500bytes,C桶此时令牌数3250 bytes,而CBS=2000bytes,因此溢出1250bytes添加到E桶,此时E桶有1750bytes。由于此时C桶大于报文长度,报文标记为绿色,C桶减少1500bytes,剩500bytes,E桶不变。

以上过程汇总如下:

-

-

-

-

-

2000

2000

2000

2000

-

1

0

1500

0

0

2000

2000

500

2000

绿色

包序号

时刻

包长

与上次添加令牌的间隔

本轮增加令牌

令牌增加后各桶令牌

报文处理后各桶剩余令牌

报文标记结果

C桶

E桶

C桶

E桶

2

1

1500

1

125

625

2000

625

500

黄色

3

2

1000

1

125

750

500

750

500

红色

4

22

1500

20

2500

2000

1750

500

1750

绿色

 

单速单桶

限速之令牌桶理解_限流_18

定义

如上图所示,为方便描述将此令牌桶称为C桶,用Tc表示桶中的令牌数量

单速单桶有2个参数:

CIR:承诺信息速率,表示向C桶中投放令牌的速率,即C桶允许传输或转发报文的平均速率;

CBS:承诺突发尺寸,表示C桶的容量,即C桶瞬间能够通过的承诺突发流量。

向桶中投放令牌

系统按照以固定的速率CIR向桶中发放令牌,最多发放到CBS结束。

即当Tc<CBS时,令牌数增加,否则不增加。

流量评估规则(数据包过桶)

对于到达的报文,用B表示报文的大小:

若B≤Tc,报文被标记为绿色,且Tc减少B;

若B>Tc,报文被标记为红色,Tc不减少。

所以,单速单桶模式不允许流量突发,当用户的流量速率小于配置的CIR时,报文被标记为绿色;当用户的流量大于CIR时直接被标记为红色。

范例

假设设备端口的CIR设置为1Mbps,CBS为2000 bytes,初始状态时C桶满(单速单桶的EBS为0,只有一个C桶)。

  • 假设第1个到达的报文是1500 bytes时,检查C桶发现令牌数大于数据包的长度,所以数据包被标为绿色,C桶减少1500 bytes,还剩500 bytes。
  • 假设1ms之后到达第2个报文1500 bytes,先填充令牌,新增令牌=CIR*时间间隔=1Mbps*1ms=1000bit=125bytes,加上C桶原来剩余的令牌500bytes,此时C桶共有625bytes,令牌不够,报文标记为红色。
  • 假设又过1ms后到达第3个报文1000 bytes,但C桶只有625 bytes,小于报文长度,因此新增令牌CIR*1ms=1000bit=125bytes,此时C桶共有750 bytes,依然不够,因此报文被标记为红色。
  • 假设又过20ms后到达第4个报文1500 bytes,但C桶只有750 bytes,小于报文长度,因此C桶新增令牌CIR*20ms=20000bit=2500bytes,C桶此时令牌数3250 bytes,而CBS=2000bytes,因此溢出1250bytes令牌被丢弃,此时C桶大于报文长度,报文标记为绿色,C桶减少1500bytes,剩500bytes。

以上过程汇总如下:

包序号

时刻

包长

与上次添加令牌的间隔

本轮增加令牌

令牌增加后C桶令牌

报文处理后C桶剩余令牌

报文标记结果

-

-

-

-

-

2000

2000

-

1

0

1500

0

0

2000

500

绿色

2

1

1500

1

125

625

625

红色

3

2

1000

1

125

750

750

红色

4

22

1500

20

2500

2000

500

绿色

 

双速率三色标记(trTCM双速双桶算法) 算法

限速之令牌桶理解_丢包_19

双速率三色标记算法业界都使用两个令牌桶,但它关注的是速率的突发,所以不像单速率三色标记算法那样把第一个桶中未使用的令牌放到第二个桶中,而是使用两个独立的令牌桶,存在两个令牌填充速率。

说明:

“双速率”是指该算法中两个令牌桶中的令牌填充速率不同。

定义

双速双桶采用RFC2698定义的双速三色标记器trTCM(A Two Rate Three Color Marker)算法对流量进行测评,根据评估结果为报文打颜色标记,即绿色、黄色和红色。
如上图所示,为方便描述将两个令牌桶称为P桶和C桶,用Tp和Tc表示桶中的令牌数量

PIR(Peak information rate):峰值信息速率,单位是 bit/s,表示向P桶中投放令牌的速率,即P桶允许传输或转发报文的峰值速率,PIR大于CIR;

CIR(Committed Information Rate):承诺信息速率,单位是 bit/s,表示向C桶中投放令牌的速率,即C桶允许传输或转发报文的平均速率;

PBS(Peak Burst Size):峰值突发尺寸,单位为 bit,表示P桶的容量,即P桶瞬间能够通过的峰值突发流量, 用来定义每次突发所允许的最大的流量尺寸;

CBS(Committed Burst Size):承诺突发尺寸,单位为 bit,表示C桶的容量,即C桶瞬间能够通过的承诺突发流量。用来定义在部分流量速率超过CIR之前 的最大突发流量尺寸;

承诺突发尺寸(CBS)必须不小于报文的最大长度。

 

常用参数信息表:

限速之令牌桶理解_ci_20

向桶中投放令牌

为方便将两个令牌桶称为C桶和P桶,C桶容量为CBS,令牌填充速率为CIR;

P桶容量为PBS,令牌填充速率为 PIR。

限速之令牌桶理解_限流_21

初始状态时C桶和P桶都是满的。

往C桶和P桶分别以CIR和PIR的速率填充令牌。因这两个令牌桶是相互独立的,当其中一个桶被填满时,这个桶新产生的令牌将会被丢弃,而另一个桶则不受影响,继续填充令牌。

系统按照PIR速率向P桶中投放令牌,按照CIR速率向C桶中投放令牌:

当Tp<PBS时,P桶中令牌数增加,否则不增加。

当Tc<CBS时,C桶中令牌数增加,否则不增加。

流量评估规则(数据包过桶)

双速率三色标记算法关注的是速率的突发,首先评估的是数据流的速率是否符合规定的突发要求,其规则是先比较P桶,再比较C桶。

用B表示到达的报文的大小,为方便用Tc和Tp表示桶中的令牌数量,Tc 和 Tp 初始化等于CBS 和PBS。

色盲模式下,在对到达报文(假设数据包大小为B)进行评估时,遵循以下规则:

  • 如果报文长度超过P桶中的令牌数Tp,则报文被标记为红色,且Tc和Tp保持 不变,
  • 如果报文长度不超过P桶中的令牌数 Tp 但超过C桶中的令牌数 Tc,则报文被标记为黄色,且 Tp=Tp-B,
  • 如果报文长度不超过C桶中的令牌数Tc,报文被标记为绿色,且 Tp=Tp-B, Tc=Tc-B。

色敏模式下,在对到达报文(假设报文大小为 B)进行评估时,遵循以下规则:

  • 如果报文已被标记为绿色且报文长度超过P桶中的令牌数Tp,则报文被标记为红色,且 Tp 和 Tc 不变。
  • 如果报文已被标记为绿色且报文长度不超过P桶中的令牌数Tp但超过C桶中的令牌数 Tc,则报文被标记为黄色,且 Tp=Tp-B,Tc 不变。
  • 如果报文已被标记为绿色且报文长度不超过C 桶中的令牌数 Tc,则报文被标记为绿色,且 Tp=Tp-B,Tc=Tc-B。
  • 如果报文已被标记为黄色,则只比较P桶,如果报文长度超过P桶中的令牌数 Tp,则报文被标记为红色,且 Tp 和 Tc 不变。
  • 如果报文已被标记为黄色,且报文长度不超过P桶的令牌数,则报文被标记为 黄色,且 Tp=Tp-B,Tc 不变。
  • 如果报文已被标记为红色,直接将报文标记为红色,Tc 和 Tp 不变。

双速双桶模式允许流量速率突发,当用户的流量速率小于配置的CIR时,报文被标记为绿色;当用户的流量大于CIR而小于PIR时,报文被标记为黄色;当用户的流量大于PIR时,报文被标记为红色。

范例

假设设备端口的CIR设置为1Mbps,PIR设置为2Mbps,CBS为2000 bytes,PBS为2000 bytes,初始状态时C桶和P桶满。

  • 第1个到达的报文假设是1500 bytes时,检查发现报文长度不超过P桶也不超过C桶,所以数据包被标为绿色,C桶和P桶都减少1500 bytes,C桶还剩500 bytes,P桶还剩500bytes。
  • 假设1ms后到达第2个报文1500 bytes,超过P桶,因此P桶新增令牌PIR*1ms=2000bit=250bytes,此时P桶共有750 bytes,依然小于报文长度。因此报文标记为红色,P桶、C桶令牌数不变。
  • 假设又过1ms后到达第3个报文1000 bytes,超过P桶,因此P桶新增令牌PIR*1ms=2000bit=250bytes,此时P桶共有1000 bytes,等于报文长度,再检查C桶,此时C桶500bytes,小于令牌数,因此C桶新增令牌CIR*2ms =2000bit =250bytes,此时C桶750bytes,仍然小于报文长度,因此报文被标记为黄色,P桶减少1000bytes,剩0bytes,C桶不变。
  • 假设又过20ms之后到达报文1500 bytes,但P桶没有令牌,不够发送报文,因此P桶新增令牌PIR*20ms=40000bit=5000bytes,超过P桶容量PBS,因此P桶=PBS=2000bytes,溢出的令牌丢弃;这样P桶有2000bytes,大于报文长度,因此比较C桶,C桶此时令牌数750bytes,小于报文长度,因此C桶新增令牌CIR*20ms=20000bit=2500bytes,大于CBS的2000 bytes,因此溢出的令牌丢弃,C桶此时令牌数2000 bytes,大于报文长度,报文被标记为绿色,C桶减少1500bytes还剩500bytes,P桶减少1500bytes还剩500bytes。

以上过程汇总如下:

-

-

-

-

-

-

-

2000

2000

2000

2000

-

1

0

1500

0

0

0

0

2000

2000

500

500

绿色

包序号

时刻

包长

与上次添加令牌的间隔

本轮增加令牌

令牌增加后各桶令牌

报文处理后各桶剩余令牌

报文标记结果

C桶

P桶

C桶

P桶

C桶

P桶

C桶

P桶

2

1

1500

1

1

125

250

500

750

500

750

红色

3

2

1000

2

1

250

250

750

1000

750

0

黄色

4

22

1500

20

20

2500

5000

2000

2000

500

500

绿色

三种令牌桶的使用场景

三种令牌桶模式之间的区别和相互关系

如下所示:

区别

单速单桶

单速双桶

双速双桶

参数

CIR和CBS

CIR、CBS和EBS

CIR、CBS、PIR和PBS

令牌投放方式

以CIR速率向C桶投放令牌。C桶满时令牌溢出。

C桶满时令牌投放到E桶。C桶和E桶都不满时,只向C桶投放令牌。

以CIR速率向C桶投放令牌,以PIR速率向P桶中投放令牌。两个桶相对独立。桶中令牌满时令牌溢出。

是否允许流量突发

不允许流量突发。报文的处理以C桶中是否有足够令牌为依据。

允许报文尺寸的突发。先使用C桶中的令牌,C桶中令牌数量不够时,使用E桶中的令牌。

允许报文速率的突发。C桶和P桶中的令牌足够时,两个桶中的令牌都使用。C桶中令牌不够时,只使用P桶中的令牌。

报文颜色标记结果

绿色或红色

绿色、黄色或红色

绿色、黄色或红色

相互关系

单速双桶模式中,如果EBS等于0,其效果和单速单桶是一样的。

双速双桶模式中,如果PIR等于CIR,其效果和单速单桶是一样的。

单速单桶的逻辑图

限速之令牌桶理解_丢包_22

单速双桶的逻辑图

限速之令牌桶理解_限流_23

当有B字节的报文传过来的时候,根据两个桶的当前容量对这个报文进行处理。EBS的作用是让超出的流量用光CBS的令牌后,如果还是无法转发,会去E桶中拿令牌,双桶可以有效的转发突发的流量。

所以双桶单速率只是有效的解决了一次单位时间内的突发流量,如果出现每时每刻都是突发流量,会被丢弃。

双速双桶的逻辑图

限速之令牌桶理解_丢包_24

某个突发流量很长一段时间不断持续的发送,为了防止此流量被丢掉,所以采用双桶双速率的方式。

例如CIR为10MB,而会经常有连续的突发流量为12MB,为了保证这种连续的突发流量传输,所以此时采用双桶双速率的模式(20MB)保证此连续的突发流量通过。

三种令牌桶模式的功能及选用场景

令牌桶模式

功能

选用场景

缺点

单速单桶

仅 用 于 限 制 带 宽,思路和配置 简单

优先级较低的业务(如企业外网HTTP流量),对于超过额度的流量直接丢弃保证其他业务,不考虑突发。

对超过单桶容量的突发流量没有任何的宽容余地。

单速双桶

限制带宽,还可以容许一部分流量突发,并且可以区分突发业务和正常业务

(根据yellow区分?)

较为重要的业务,容许有突发的业务(如企业邮件数据),对于突发流量有宽容。

思路较单速单桶复杂,需要考虑 E桶的容量。

双速双桶

限制带宽,可以进行流量带宽划分,可以区别带宽小于CIR还是在CIR与PIR之间

重要业务,可以更好的监控流量的突发程度,对流量分析起到指导作用。

方案部署前需要充分考虑 CIR,CBS,PIR 和 PBS的取值,并且根据不同业务做区分。

单速双桶关注报文尺上的突发,其令牌添加方式和报文处理流程比较简单;双速双桶关注速率上的突发,其令牌添加方式和报文处理流程相对复杂。

单速和双速各有优点,不同的实现方式决定了其具有一定的性能差异(丢包率、突发流量处理性能、大小包混合转发性能、数据转发平缓程度等),在实际应用中,应针对不同的流量特征选择恰当的标记方式。

  • 如果只是为了限制带宽,使用单速单桶。
  • 如果在限制带宽的基础上,还要对输入流量的突发情况进行区分,做不同的标记处理,则使用单速双桶。注意:标记为yellow的动作一定要同标记为green的动作的配置是不一样,否则限速效果与单速单桶一样。
  • 如果在限制带宽的基础上,还要对输入流量的带宽情况进行区分,区分出带宽是小于CIR还是在CIR~PIR之间,则使用双速双桶。注意:标记为yellow的动作也要同标记为green的动作配置得不一样,否则限速效果与单速单桶一样。

参数设置

CIR设置

在令牌桶算法中,CIR设置越大,令牌产生的速率越大,则分组获得令牌就越多,流向网络的流量也就越大,因此,CIR的大小是控制流入网络中流量多少的关键。

CBS/EBS设置

CBS

令牌桶桶深CBS也是一个重要参数,CBS的值越大,C桶中可以积累令牌的数目也越多,允许通过的报文尺寸之和就越大。由于设备进行的是逐包转发,CBS的值不应该小于当前网络上允许传输的报文的最大长度。

够发送到网络中的最大突发流量都大致与令牌桶的大小成正比。

例如,在单速单桶模式下,假设要把流量限定在10Mbit/s,而CBS值太小(如设置成1000byte)。如果某个时间段内流量的报文,每个报文大小都大于1000byte,那么这些报文全都被丢弃。这段时间内,没有报文被转发,报文的转发速率为0,导致网络资源被浪费,业务也出现异常。

那是不是CBS的值越大就越好呢?显然不是。CBS值太大,会失去限速的意义。例如,假设要把流量限定在10Mbit/s,CBS设置成7200Mbyte。某个时刻,令牌桶中的令牌已满,如果接下来1小时内流量的报文,其报文长度不一,但共计7200Mbyte,这些报文都能获得令牌并被转发,那么这段时间内的报文速率为16Mbit/s(7200M * 8 / 3600)而不是10Mbit/s,即没有实现限速。

EBS

对于超额突发流量 EBS,单位为 bit。在华为设备上,CBS 与 EBS 是由两个单独的令牌 桶承载的,CBS 与 EBS 的大小没有什么必然联系。

如果不允许有突发流量的话,EBS 只要设置成 0。要使令牌桶有扩展突发能力只要 EBS 设置的大于 0。

令牌桶算法的带宽参数设置取决于实际网络业务的限速需要。桶深是一个重要参数,具体该如何设置,则取决于具体的业务流量情况。原则上,桶深需要满足如下条件:

  • 桶深>=MTU
  • 桶深>=业务流量的正常突发

条件1比较直观,容易操作;但条件2实际操作比较困难,因此出现了一些经验性的计算公式,例如:

桶深(Bytes)=带宽(kbps) * RTT(ms) / 8,其中的RTT是TCP协议的往返时间,通常取200ms。

对华为交换机总结的经验性公式为:

  • 带宽<=100Mbps 时,桶深(Bytes)=带宽(Kbps) * 1000(ms)/8
  • 带宽>100Mbps 时,桶深(Bytes)=100,000(Kbps) * 1000(ms)/8

CAR之后的带宽计算是基于整包的,即不仅仅包括IP头及IP净荷。例如,对于以太网业务,还包含了帧头和CRC,但不包含前导码、帧间隔。完整的以太帧如下(长度单位:字节):

限速之令牌桶理解_丢包_25

CAR之后的带宽计算不包括其中的Inter frame gap、Preamble、SFD。

除了桶深,突发流量速率 PIR 的设置也是方案使用和命令配置中不可避免的,在工程上 PIR 的速率一般定义为 CIR 的 1.5 倍,过大的 PIR 会导致设备过高的负荷,反而适得其反。

分布式集群限流

背景

为什么要分布式限流

限速之令牌桶理解_ci_26

当应用为单点应用时,只要应用进行了限流,那么应用所依赖的各种服务也都得到了保护。

限速之令牌桶理解_丢包_27

但线上业务出于各种原因考虑,多是分布式系统,单节点的限流仅能保护自身节点,但无法保护应用依赖的各种服务,并且在进行节点扩容、缩容时也无法准确控制整个服务的请求限制。

限速之令牌桶理解_限流_28

在多机部署场景下,对单点的限流,则不能达到最好效果,需要引入分布式限流。

虽然给每台机器平均分配限流配额可以达到限流的目的,但是由于机器性能,流量分布不均以及计算数量动态变化等问题,单机限流在分布式场景中的效果总是差强人意。

分布式限流的算法,依然可以采用令牌桶算法,只不过将令牌桶的发放、存储改为全局的模型。

redis + lua 集群限流

分布式限流最简单的实现就是利用中心化存储,即将单机限流存储在本地的数据存储到同一个存储空间中,如常见的Redis等。

限速之令牌桶理解_限流_29

 

真正实现中,可以采用redis+lua的方式,通过把逻辑放在redis端,来减少调用次数。

为实现限流算法,需要反复调用 Redis 查询与计算,一次限流判断需要多次请求较为耗时。因此我们采用编写 Lua 脚本运行的方式,将运算过程放在 Redis 端,使得对 Redis 进行一次请求就能完成限流的判断。

lua的逻辑如下:

  1. redis中存储剩余令牌的数量cur_token,和上次获取令牌的时间last_time,存储桶的大小。
  2. 在每次申请令牌时,可以根据(当前时间cur_time - last_time)的时间差 乘以 令牌发放速率,算出当前可用令牌数。
  3. 如果有剩余令牌,则准许请求通过;否则不通过。

 

中心控制器(center control)集群限流

中心控制器定期的从各个分布式节点中采集流量数据;采集完了之后,基于各个中心控制器在上一个时间周期内的流量比例,分配下一个时间周期内的令牌数量。

竞品分析

当然,市面上也有比较成熟的限流工具和框架。如:

Google出品的Guava中基于令牌桶实现的限流组件,拿来即用;

以及alibaba开源的面向分布式服务架构的流量控制框架Sentinel更会让你爱不释手,它是基于滑动窗口实现的。

令牌桶限速实现

dpdk 单速率三色算法

DPDK提供了丰富的基础库,其中就有利用令牌桶来实现meter功能,可以参考 rte_meter.h 文件;

首先介绍下DPDK的两个函数,这也是在算法的实现中需要用到的两个函数,摘抄自DPDK官方文档:

static uint64_t rte_get_timer_cycles(void )
Get the number of cycles since boot from the default timer.

static uint64_t rte_get_timer_hz(void)
Get the number of cycles in one second for the default timer.

初始化

struct rte_meter_srtcm {
uint64_t time; /* 最后一次更新C和E桶的时间*/
uint64_t tc; /* C桶当前可用令牌数*/
uint64_t te; /* E桶当前可用令牌数*/

uint64_t cbs; /* cbs数值,C桶的总容量*/
uint64_t ebs; /* ebs数值,E桶的总容量*/
uint64_t cir_period; /* 每隔cir_period 个 cycle,更新C桶*/
uint64_t cir_bytes_per_period; /*每次更新C桶所需添加的令牌数*/
};

注:cbs, ebs, cir_period, cir_bytes_per_period 一经确定,如果不更改配置,数据包过桶是不会发生变化的;time, tc, te 在数据包过桶期间是发送变化的;


int
rte_meter_srtcm_config(struct rte_meter_srtcm *m, struct rte_meter_srtcm_params *params)
{
uint64_t hz;

/* Check input parameters */
if ((m == NULL) || (params == NULL)) {
return -1;
}

if ((params->cir == 0) || ((params->cbs == 0) && (params->ebs == 0))) {
return -2;
}

/* Initialize srTCM run-time structure */
hz = rte_get_tsc_hz();
m->time = rte_get_tsc_cycles();
m->tc = m->cbs = params->cbs;
m->te = m->ebs = params->ebs;
rte_meter_get_tb_params(hz, params->cir, &m->cir_period, &m->cir_bytes_per_period);

RTE_LOG(INFO, METER, "Low level srTCM config: \n"
"\tCIR period = %" PRIu64 ", CIR bytes per period = %" PRIu64 "\n",
m->cir_period, m->cir_bytes_per_period);

return 0;
}


/*
每隔 1s/CIR 时间添加一个令牌;
1s可以转化为 cycles,即每个n个cycles往令牌桶中添加一个令牌;
一个令牌可以理解为1B;
*/
static void
rte_meter_get_tb_params(uint64_t hz, uint64_t rate, uint64_t *tb_period, uint64_t *tb_bytes_per_period)
{
double period = ((double) hz) / ((double) rate);

if (period >= RTE_METER_TB_PERIOD_MIN) {
*tb_bytes_per_period = 1;
*tb_period = (uint64_t) period;
} else {
*tb_bytes_per_period = (uint64_t) ceil(RTE_METER_TB_PERIOD_MIN / period);
*tb_period = (hz * (*tb_bytes_per_period)) / rate;
}
}

PARAMS:
struct rte_meter_srtcm_params app_srtcm_params[] = {
{.cir = 1000000 * 46, .cbs = 2048, .ebs = 2048},
};

桶中添加令牌以及流量过桶

针对每个包,都会进行颜色判断,色盲模式的判断比较简单,对应的函数如下:

/*
blind check:此中为 色盲模式;
*/
static inline enum rte_meter_color
rte_meter_srtcm_color_blind_check(struct rte_meter_srtcm *m,
uint64_t time,
uint32_t pkt_len)
{
uint64_t time_diff, n_periods, tc, te;

/* Bucket update */
time_diff = time - m->time;
n_periods = time_diff / m->cir_period;
m->time += n_periods * m->cir_period;//m->time = time。强行增加阅读难度,更新m->time

/* 先往C桶添加令牌,C桶添加满之后再往E桶添加令牌 */
tc = m->tc + n_periods * m->cir_bytes_per_period; //更新当前C桶可用令牌数
te = m->te;
if (tc > m->cbs) {
te += (tc - m->cbs);
if (te > m->ebs)
te = m->ebs;
tc = m->cbs;
}

/* Color logic */
//C桶可用令牌足够,返回绿色。
if (tc >= pkt_len) {
m->tc = tc - pkt_len;
m->te = te;
return e_RTE_METER_GREEN;
}
//C桶不够,用E桶判断。
if (te >= pkt_len) {
m->tc = tc;
m->te = te - pkt_len;
return e_RTE_METER_YELLOW;
}

m->tc = tc;
m->te = te;
return e_RTE_METER_RED;
}

多线程处理

多线程处理的基本思想,如下图所示:

  • 一个全局令牌桶
    随着时间的推移,每次放入令牌仅仅放入全局令牌桶。为什么不放入线程令牌桶?假设需要限速的报文到了不同的线程,并且每个线程流量不同,那么对于每个线程放入令牌的数量就不得而知了。
  • 每个线程拥有独立的子令牌桶
    子令牌桶只消费令牌,不放入令牌。当子令牌桶的令牌不够时,从全局令牌桶索取令牌。

限速之令牌桶理解_ci_30

 

详细流程

下面将用流程图的形式来描述多线程令牌桶的实现。在最后会介绍这种令牌桶算法可能存在的问题。

限速之令牌桶理解_限流_31

 

dpdk 单速率三色算法优化

主要涉及到 

1)报文平滑优化;通过借贷方式

2)dpdk 除法的优化;

3)引入扩大因子 解决 CIR太大时 cir_period 过小的问题


其他优化

平滑策略,如下所示

  • 防止单条连接长时间没有包通过

背景:

比如一条长连接,由于限速,后续长时间(比如200ms),没有一个包可以通过;这样会流量不太平滑;

解决:

理想状态,比如对于一个长连接,每隔200ms,尽可能的保证至少有一个数据包可以通过;

那么就可以基于连接的五元组进行hash,然后以hash值在bitmap中查找;

没有找到,则首次运行通过,不检查 pkt_len 和 tc,tc-= pkt_len;

查找到,则判断 pkt_len 和 tc 的大小关系,决定是否通过;

每隔200ms,将 bitmap 清空;

注:bitmap标志位需要定期清理的;

  • tcp重传数据包允许通过

背景:第一个包被丢弃,client重传,有可能继续被丢弃,可以设置重传的包可以通过;

解决:基于五元组+seq进行hash,然后设置bitmap的标志位,如果该标志位设置过了,则允许通过;注:bitmap标志位需要定期清理的;

  • 一个连接的首包允许通过

解决:基于五元组进行hash,查看bitmap,没有设置,则允许通过;注:bitmap标志位需要定期清理的;

限流规则/参数的合理性

限流规则包含三个部分:时间粒度,接口粒度,最大限流值。限流规则设置是否合理直接影响到限流是否合理有效。

  • 限流时间粒度

我们既可以选择 1 秒钟不超过 1000 次,也可以选择 10 毫秒不超过 10 次,还可以选择 1 分钟不超过 6 万次;

虽然看起这几种限流规则都是等价的,但过大的时间粒度会达不到限流的效果,比如限制 1 分钟不超过 6 万次,就有可能 6 万次请求都集中在某一秒内;

相反,过小的时间粒度会削足适履导致误杀很多本不应该限流的请求,因为接口访问在细时间粒度上随机性很大。

所以,尽管越细的时间粒度限流整形效果越好,流量曲线越平滑,但也并不是越细越合适。

对于访问量巨大的接口限流,比如秒杀,双十一,这些场景下流量可能都集中在几秒内,QPS 会非常大,几万甚至几十万,需要选择相对小的限流时间粒度。相反,如果接口 QPS 很小,建议使用大一点的时间粒度,比如限制 1 分钟内接口的调用次数不超过 1000 次;

参考

​基于DPDK的多核令牌桶算法​

​单速双桶、双速双桶原理​

​CAR​

​流量评估与令牌桶技术​

​QoS 技术白皮书​

​QOS-HCIE 知乎​