QOS令牌桶实现

实际中比较常见的有两种实现方式:

  1. 周期性的添加,添加的时间间隔就是令牌桶的容量与添加速率的比值:△t=CBS/CIR,每次添加的令牌数为 CBS 个。
  2. 一次性添加,添加令牌的数量是△t×CIR(△t 是当前时间与上次添加令牌的时间之差),且是一次添加完毕,并不是按照一定速率添加。

当前业界都采用的第二种方式,第一种方式涉及定时器精度不太好控制。

由于报文过令牌桶的时候我们很容易能获取到的是报文长度和时间,这两个度量我们分别取单位为:

1个字节和1个cycle,然后我们使用这两个单位来展开令牌桶的换算:

1秒时间单位内有CIR(CIR已经换算成字节了)个字节,而1秒的时间单位有HZ * 1个cycle,利用这层关系我们假设:

CIR * 1个字节 = HZ * 1个cycle,换算后我们可以得到两个公式:

1个字节  = HZ/CIR * 1个cycle
1个cycle = CIR/HZ * 1个字节

两种实现方式的基本思想是一直的,只是细节上有一些差别,我们下面具体来看

2.1 第一种实现方式

根据公式:1个字节  = HZ/CIR * 1个cycle 我们来实现第一种方式的令牌桶,也是DPDK当前的实现方式,代码分散在dequeue的各个出队状态机里面。

2.1.1 基本实现

当CIR太大的时候,1个字节计算出来的cycle数会为小数,为了解决这个问题,我们引入扩大因子,扩大因子越大,分辨率越高,同时需要考虑HZ和最大支持的CIR的关系和溢出的风险,扩大因子又不能太大,那么公式就变成如下:

1个字节  = (HZ/CIR * 1个cycle) << 5 (扩大因子) ①

以此为依据我们看下过srTCM的整个过程:

获取当前的cycle,记为new_cycle

获取这段期间的cycle数,记为diff_cycle = new_cycle – old_cycle

获取diff_cycle的字节数 diff_bytes = diff_cycle/ * 扩大因子

然后使用diff_bytes过桶:

1、计算TC 和TE:

IF tc + diff_bytes >= CBS,

    tc = CBS;

    diff_bytes -= (CBS – tc);

   IF te + diff_bytes >= EBS

       te = EBS;

    ELSE

       te += diff_bytes;

ELSE

tc += diff_bytes;

2、计算颜色

IF tc >= Pkt_len

   Color = GREE;

   Tc -= Pkt_len;

ELSE IF te >= Pkt_len

   Color = YELLOW;

   Te -= Pkt_len;

ELSE

   Color = RED;

2.1.2 优化方法

上面的实现由两个地方可以优化:

1、diff_bytes 使用了除法,这个代码是很昂贵的,DPDK 实现了一个使用移位代替除法的算法,来提高性能,但没怎么看明白。

我们可以使用空间换时间的想法,使用以下的方法,提高整个过桶的过程:

  • 根据公式:1个字节  = HZ/CIR * 1个cycle * << 5(扩大因子),我们已经知道了一个字节代表的cycle数,那么可以可以把所有的都转化为cycle的时间单位来计算。

创建令牌桶的时候,CBS、EBS 根据公式换算成 cycles数保存,同时计算数组(下标是字节数)L2T[1 … 512] = [x cycle …… ycycle],为过桶做好准备。

 

过桶的时候,获取报文长度pkt_len,然后计算cycle,公式如下:

tmp_len = pkt_len / 扩大因子,然后计算tc_cycle,这里考虑tmp_len的计算,扩大因子不能太大,32是一个比较好的值。

IF tmp_len > 512

    tc_cycle = (tmp_len / 512) * L2T[512] + L2T[tmp_len & 511];

ELSE

tc_cycle = L2T[tmp_len];

然后在根据tc_cycle去过桶。

解决了除法的问题,同时使用数组和移位加快计算,不在乎内存的话,L2T的数组可以定义为MTU的大小,任何报文长度都可以根据数组一次得到tc_cycle。

2、过桶的时候,使用的是比较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桶不变。

……………………

整个过程如下表所示:

序号

时间(ms)

报文长度

时间间隔

本轮新增令牌

新的后TC

新的后TE

剩余TC

剩余TE

颜色

-

-

-

-

-

2000

2000

2000

2000

-

1

0

1500

0

0

2000

2000

500

2000

GREE

2

1

1500

1

125

625

2000

625

500

YELLOW

3

2

1500

1

125

750

500

750

500

RED

4

22

1500

20

2500

2000

1750

500

1750

GREE

 

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

IF tc > 0

   Color = GREE;

   Tc -= Pkt_len;

ELSE IF te > 0

   Color = YELLOW;

   Te -= Pkt_len;

ELSE

   Color = RED;

 

上面的过程变成:

序号

时间(ms)

报文长度

时间间隔

本轮新增令牌

新的后TC

新增后TE

剩余TC

剩余TE

颜色

-

-

-

-

-

2000

2000

2000

2000

-

1

0

1500

0

0

2000

2000

500

2000

GREE

2

1

1500

1

125

625

2000

-875

2000

GREE

3

2

1500

1

125

-750

2000

-750

500

YELLOW

4

22

1500

20

2500

1750

500

250

500

GREE

 

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

2.2 第二种实现方式

根据公式:1个cycle = CIR/HZ * 1个字节,我们来实现第二种方式的令牌桶。

当CIR 太小的时候,这个计算出来的值会为小数,同第一种方式,我们引入扩大因子:

1个cycle * << 17 = CIR/HZ * 1个字节 * << 17, 扩大因子VPP使用的是 1 << 17

我们现在把1个cycle * 217 称为新的时间单位,后续计算都以这个新的时间单位为基准。

以此为依据我们看下过srTCM的整个过程:

获取当前的cycle,记为new_cycle,单位为新的时间单位,计算为cycle >> 17。

获取这段期间的cycle数,记为diff_cycle = new_cycle – old_cycle(单位也是新的时间单位)

获取diff_cycle的字节数 diff_bytes = diff_cycle * CIR/HZ * 1个字节 * << 17

然后在根据diff_bytes去过桶,实现和上面的流程一致。

为了考虑乘法溢出的可能,可以使用64位存储。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值