区块链技术博客
www.b2bchain.cn

源码解读五:流量整型算法实现分析求职学习资料

D0b2wT.gif

本文介绍了源码解读五:流量整型算法实现分析求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

源码解读五:流量整型算法实现分析

[TOC]

算法简述

上文我们分析了 Sentinel 中的滑动窗口数据统计算法。在了解了滑动窗口机制后,这篇文章我们来重点分析下 FlowSlot 的代码实现。FlowSlot 是 Sentinel 内置的 8 个ProcessorSlot 中最重要最核心的实现,因为这个 Slot 负责的内容就是 Sentinel 中的核心:流量整型。

流量整型,引用百度的定义说明:是一种主动的对流量输出速率进行调整的措施,其主要目的通常在于限制某一网络的某一连接的流量和突发。

流速调整常见的有两种处理手段:漏桶算法和令牌桶算法。

漏桶算法可以简单的想象存在着一个请求桶。外部的请求就像水滴一样一滴滴流入这个桶,而桶的底部有一个小洞,桶内的水会以均匀的速度流出,也就意味着这些请求被处理。漏桶算法可以很好的均匀流量。这是优点,也是一些场景下的不足之处。假定系统当前突发的涌入了一些请求,而系统当前处于比较空闲的状态,完全有能力消化掉这些突发请求。但是漏桶算法处理请求的速度是均匀的,此时就导致系统的处理能力被闲置了。也就是无法有效的高效处理突发流量。

令牌桶则是为了处理突发流量下的一种不同的算法。令牌桶算法可以想象存在着一个存储“许可”的桶。系统按照恒定的速率往桶内放置“许可”,许可桶本身存在容量上限,如果系统放置的许可超出了上限,则会被丢弃。而外部的请求进来,每次都要申请足够数量的许可,只有许可申请成功的情况下请求才能被处理。如果请求无法申请到足够的许可,请求或许等待,或者被丢弃。显然,在有突发流量的时候,请求可以一次性消耗完毕桶内所有的令牌。这一特性,使得令牌桶特别适合于处理突发的流量。

在 Sentinel 中,进行流量整型的主要是接口 TrafficShapingController 。该接口定义了方法 canPass 用于判定当前请求是否允许被执行。下面我们就来分析下这个流量整型接口。

代码分析

这个接口的类图如下

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201029014124.png” style=”zoom:50%;” />

先来大致介绍下这个接口的使用流程。

在 FlowSlot 的实现中,其会调用方法FlowRuleChecker#checkFlow来判断当前请求是否允许通过。而该方法内部的逻辑是获取当前系统内所有的 FlowRule 实例,每一个 FlowRule 实例按照规则,系统都会为其初始化一个 TrafficShapingController 实例。使用这个 TrafficShapingController 实例来判断这个请求是否允许被放行。此时就是这个接口发挥作用的时候。这个流程我们还会在后续详细分析,这里先忽略,先关注 TrafficShapingController 的具体实现。如类图所示,这个接口 Sentinel 框架为我们默认提供了四种实现。

DefaultController

默认流量整形控制器。默认流量整型控制器的对超出阈值的流量的处理逻辑是直接拒绝。下面来看下其对于 canPass 方法的实现流程,如图所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201106171751.png” alt=”image-20201106171750850″ style=”zoom: 80%;” />

这边有个流程需要展开说明下,也就是尝试申请未来许可,也就是方法StatisticNode#tryOccupyNext。这个算法直接看代码实现的话会有一些晦涩。在这里我们先通过一个例子来说明其设计思路。

假定我们当前有一个取样大小为 4 ,统计周期为 1S 的滑动窗口。系统允许的 QPS 为 40,这就是说在一个统计周期中,最大记录的许可数不能超过 40 。该滑动窗口当前的情况如下图所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108232149.png” alt=”image-20201108232149571″ style=”zoom:50%;” />

黑色竖线代表当前的时间戳节点,绿色横线代表已经流逝的时间,红色横线代表时间戳所在的取样窗口未来剩余的时间。下方的绿色格子代表取样窗口,中间的数字代表该取样窗口内统计到数字。

从图中可以看出,该滑动窗口内当前已经记录了 30 个许可。如果此时要再申请 30 个许可,就会超出系统的阈值,那么显然是在当前的取样窗口中无法完成的。因此只能像未来还未申请到的取样窗口去请求许可。

要向未来的取样窗口去申请许可,就需要确定,当前的取样窗口失效多少个之后,才能释放出足够的许可。为了计算这个结果,我们临时用另外一个滑动窗口来计算该滑动窗口内的总许可数,如下。

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108232818.png” alt=”image-20201108232818199″ style=”zoom:50%;” />

初始情况下,用于统计的滑动窗口与当前的滑动窗口是一致的,当前已经分配了 30 个许可,显然无法再分配 30 个许可。那么滑动窗口右移一个取样窗口的长度,就会变成下面的情况

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108234401.png” alt=”image-20201108234401413″ style=”zoom:50%;” />

此时滑动窗口内许可的数量是 20 ,还是不够分配。继续右移一个取样窗口的长度,变为如下情况

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108234440.png” alt=”image-20201108234440597″ style=”zoom:50%;” />

此时滑动窗口的许可总数是 10 ,足够分配 30 个许可了。这就意味着需要等待 2 个取样窗口的时间外加之前取样窗口剩余的时间,也就是红线部分代表的时间,滑动窗口内才会足够的许可数量来满足。

当然,在等待的过程中,其他线程也可能会来申请许可,因此单纯等待是不可取的,当明确时间后,就需要首先将这些未来的许可都提前占据,避免被其他线程获取到或者占据到。

总结来说,申请未来许可可以细分为两个步骤:

  • 从当前时间戳计算出当前滑动窗口的起始点时间戳。声明一个以该时间戳为起始点的滑动窗口,不断向右滑动取样窗口的长度,直到滑动窗口可以满足未来许可的申请数量。通过滑动窗口移动的次数和取样窗口的长度以及当前时间戳在自身取样窗口所谓的位置,可以得到当前线程为获得许可需要等待的时间。
  • 以上面的时间为依据,提前占据未来的许可,避免被其他线程抢夺。

第二个步骤,在 DefaultController 的代码中实现了,也就是申请占据未来许可这段。而第一个步骤,就是方法StatisticNode#tryOccupyNext的实现内容。下面我们来看下代码流程,如下:

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201109011722.png” alt=”image-20201109011722343″ style=”zoom:80%;” />

到这里,DefaultController 的主要流程就分析完了。这是 Sentinel 中的流控默认实现,支持高优先级的请求在允许范围内提前消耗系统未来许可,从而保证高优先请求的优先响应。

当 DefaultController 抛出 PriorityWaitException 异常的时候,处理器槽 StatisticSlot 会捕获这个异常,该异常不会中断请求,而是会让继续执行。只不过统计节点此时只需要新增运行中线程数即可,因为因为访问统计在抛出异常之前的DefaultController.canPass方法中已经完成了。

RateLimiterController

相比于上者,RateLimiterController 的思路则简单的多。RateLimiterController 的流控思路就是排队等待。每次新的请求产生的时候,就计算产生该请求对应的许可需要耗费的时间,该时间加上上次请求的时间点减去当前时间点就得到了本次请求需要等待的时间。如果这个时间小于最大排队时间,则当前线程休眠该时间后处理该请求;否则阻断该请求。

RateLimiterController 的实现并没有非常严格的代码限制,不过通常而言,其实现的效果是所有的请求是被排队后“依次”发生。来看下其canPass方法的实现逻辑,整体流程如下

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201109180308.png” alt=”image-20201109180302012″ style=”zoom: 33%;” />

这个流程并不是一个精确计算的排队实现,不过对于流控而言,过于精确的操作,会对原本的请求有一定的负面影响。因此实现成这样,也是可以理解的。

WarmUpController

算法分析

对于一些系统而言,单纯对于阈值的限制仍然是不够的。一些系统能够承受较高的 QPS ,但是系统的承受能力有明显的周期特性。比如说系统在长期无使用的时候,对外部请求的响应时间会变长。而当访问不停发生的时候,系统的吞吐就会逐渐提高上来,延迟降低,表现为 QPS 升高。这种情况下,我们就需要对系统进行”预热“。也就是在系统刚启动,或者长时间无流量的情况下,将限制阈值压在比较低的范围。如果访问持续发生,按照一定的速度提升 QPS 阈值,直到达到系统的上限。

限流器对系统 QPS 的限制和时间关系如下所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201202183722.png” style=”zoom:50%;” />

源码解读五:流量整型算法实现分析

[TOC]

算法简述

上文我们分析了 Sentinel 中的滑动窗口数据统计算法。在了解了滑动窗口机制后,这篇文章我们来重点分析下 FlowSlot 的代码实现。FlowSlot 是 Sentinel 内置的 8 个ProcessorSlot 中最重要最核心的实现,因为这个 Slot 负责的内容就是 Sentinel 中的核心:流量整型。

流量整型,引用百度的定义说明:是一种主动的对流量输出速率进行调整的措施,其主要目的通常在于限制某一网络的某一连接的流量和突发。

流速调整常见的有两种处理手段:漏桶算法和令牌桶算法。

漏桶算法可以简单的想象存在着一个请求桶。外部的请求就像水滴一样一滴滴流入这个桶,而桶的底部有一个小洞,桶内的水会以均匀的速度流出,也就意味着这些请求被处理。漏桶算法可以很好的均匀流量。这是优点,也是一些场景下的不足之处。假定系统当前突发的涌入了一些请求,而系统当前处于比较空闲的状态,完全有能力消化掉这些突发请求。但是漏桶算法处理请求的速度是均匀的,此时就导致系统的处理能力被闲置了。也就是无法有效的高效处理突发流量。

令牌桶则是为了处理突发流量下的一种不同的算法。令牌桶算法可以想象存在着一个存储“许可”的桶。系统按照恒定的速率往桶内放置“许可”,许可桶本身存在容量上限,如果系统放置的许可超出了上限,则会被丢弃。而外部的请求进来,每次都要申请足够数量的许可,只有许可申请成功的情况下请求才能被处理。如果请求无法申请到足够的许可,请求或许等待,或者被丢弃。显然,在有突发流量的时候,请求可以一次性消耗完毕桶内所有的令牌。这一特性,使得令牌桶特别适合于处理突发的流量。

在 Sentinel 中,进行流量整型的主要是接口 TrafficShapingController 。该接口定义了方法 canPass 用于判定当前请求是否允许被执行。下面我们就来分析下这个流量整型接口。

代码分析

这个接口的类图如下

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201029014124.png” style=”zoom:50%;” />

先来大致介绍下这个接口的使用流程。

在 FlowSlot 的实现中,其会调用方法FlowRuleChecker#checkFlow来判断当前请求是否允许通过。而该方法内部的逻辑是获取当前系统内所有的 FlowRule 实例,每一个 FlowRule 实例按照规则,系统都会为其初始化一个 TrafficShapingController 实例。使用这个 TrafficShapingController 实例来判断这个请求是否允许被放行。此时就是这个接口发挥作用的时候。这个流程我们还会在后续详细分析,这里先忽略,先关注 TrafficShapingController 的具体实现。如类图所示,这个接口 Sentinel 框架为我们默认提供了四种实现。

DefaultController

默认流量整形控制器。默认流量整型控制器的对超出阈值的流量的处理逻辑是直接拒绝。下面来看下其对于 canPass 方法的实现流程,如图所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201106171751.png” alt=”image-20201106171750850″ style=”zoom: 80%;” />

这边有个流程需要展开说明下,也就是尝试申请未来许可,也就是方法StatisticNode#tryOccupyNext。这个算法直接看代码实现的话会有一些晦涩。在这里我们先通过一个例子来说明其设计思路。

假定我们当前有一个取样大小为 4 ,统计周期为 1S 的滑动窗口。系统允许的 QPS 为 40,这就是说在一个统计周期中,最大记录的许可数不能超过 40 。该滑动窗口当前的情况如下图所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108232149.png” alt=”image-20201108232149571″ style=”zoom:50%;” />

黑色竖线代表当前的时间戳节点,绿色横线代表已经流逝的时间,红色横线代表时间戳所在的取样窗口未来剩余的时间。下方的绿色格子代表取样窗口,中间的数字代表该取样窗口内统计到数字。

从图中可以看出,该滑动窗口内当前已经记录了 30 个许可。如果此时要再申请 30 个许可,就会超出系统的阈值,那么显然是在当前的取样窗口中无法完成的。因此只能像未来还未申请到的取样窗口去请求许可。

要向未来的取样窗口去申请许可,就需要确定,当前的取样窗口失效多少个之后,才能释放出足够的许可。为了计算这个结果,我们临时用另外一个滑动窗口来计算该滑动窗口内的总许可数,如下。

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108232818.png” alt=”image-20201108232818199″ style=”zoom:50%;” />

初始情况下,用于统计的滑动窗口与当前的滑动窗口是一致的,当前已经分配了 30 个许可,显然无法再分配 30 个许可。那么滑动窗口右移一个取样窗口的长度,就会变成下面的情况

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108234401.png” alt=”image-20201108234401413″ style=”zoom:50%;” />

此时滑动窗口内许可的数量是 20 ,还是不够分配。继续右移一个取样窗口的长度,变为如下情况

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108234440.png” alt=”image-20201108234440597″ style=”zoom:50%;” />

此时滑动窗口的许可总数是 10 ,足够分配 30 个许可了。这就意味着需要等待 2 个取样窗口的时间外加之前取样窗口剩余的时间,也就是红线部分代表的时间,滑动窗口内才会足够的许可数量来满足。

当然,在等待的过程中,其他线程也可能会来申请许可,因此单纯等待是不可取的,当明确时间后,就需要首先将这些未来的许可都提前占据,避免被其他线程获取到或者占据到。

总结来说,申请未来许可可以细分为两个步骤:

  • 从当前时间戳计算出当前滑动窗口的起始点时间戳。声明一个以该时间戳为起始点的滑动窗口,不断向右滑动取样窗口的长度,直到滑动窗口可以满足未来许可的申请数量。通过滑动窗口移动的次数和取样窗口的长度以及当前时间戳在自身取样窗口所谓的位置,可以得到当前线程为获得许可需要等待的时间。
  • 以上面的时间为依据,提前占据未来的许可,避免被其他线程抢夺。

第二个步骤,在 DefaultController 的代码中实现了,也就是申请占据未来许可这段。而第一个步骤,就是方法StatisticNode#tryOccupyNext的实现内容。下面我们来看下代码流程,如下:

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201109011722.png” alt=”image-20201109011722343″ style=”zoom:80%;” />

到这里,DefaultController 的主要流程就分析完了。这是 Sentinel 中的流控默认实现,支持高优先级的请求在允许范围内提前消耗系统未来许可,从而保证高优先请求的优先响应。

当 DefaultController 抛出 PriorityWaitException 异常的时候,处理器槽 StatisticSlot 会捕获这个异常,该异常不会中断请求,而是会让继续执行。只不过统计节点此时只需要新增运行中线程数即可,因为因为访问统计在抛出异常之前的DefaultController.canPass方法中已经完成了。

RateLimiterController

相比于上者,RateLimiterController 的思路则简单的多。RateLimiterController 的流控思路就是排队等待。每次新的请求产生的时候,就计算产生该请求对应的许可需要耗费的时间,该时间加上上次请求的时间点减去当前时间点就得到了本次请求需要等待的时间。如果这个时间小于最大排队时间,则当前线程休眠该时间后处理该请求;否则阻断该请求。

RateLimiterController 的实现并没有非常严格的代码限制,不过通常而言,其实现的效果是所有的请求是被排队后“依次”发生。来看下其canPass方法的实现逻辑,整体流程如下

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201109180308.png” alt=”image-20201109180302012″ style=”zoom: 33%;” />

这个流程并不是一个精确计算的排队实现,不过对于流控而言,过于精确的操作,会对原本的请求有一定的负面影响。因此实现成这样,也是可以理解的。

WarmUpController

算法分析

对于一些系统而言,单纯对于阈值的限制仍然是不够的。一些系统能够承受较高的 QPS ,但是系统的承受能力有明显的周期特性。比如说系统在长期无使用的时候,对外部请求的响应时间会变长。而当访问不停发生的时候,系统的吞吐就会逐渐提高上来,延迟降低,表现为 QPS 升高。这种情况下,我们就需要对系统进行”预热“。也就是在系统刚启动,或者长时间无流量的情况下,将限制阈值压在比较低的范围。如果访问持续发生,按照一定的速度提升 QPS 阈值,直到达到系统的上限。

限流器对系统 QPS 的限制和时间关系如下所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201202183722.png” style=”zoom:50%;” />

源码解读五:流量整型算法实现分析

[TOC]

算法简述

上文我们分析了 Sentinel 中的滑动窗口数据统计算法。在了解了滑动窗口机制后,这篇文章我们来重点分析下 FlowSlot 的代码实现。FlowSlot 是 Sentinel 内置的 8 个ProcessorSlot 中最重要最核心的实现,因为这个 Slot 负责的内容就是 Sentinel 中的核心:流量整型。

流量整型,引用百度的定义说明:是一种主动的对流量输出速率进行调整的措施,其主要目的通常在于限制某一网络的某一连接的流量和突发。

流速调整常见的有两种处理手段:漏桶算法和令牌桶算法。

漏桶算法可以简单的想象存在着一个请求桶。外部的请求就像水滴一样一滴滴流入这个桶,而桶的底部有一个小洞,桶内的水会以均匀的速度流出,也就意味着这些请求被处理。漏桶算法可以很好的均匀流量。这是优点,也是一些场景下的不足之处。假定系统当前突发的涌入了一些请求,而系统当前处于比较空闲的状态,完全有能力消化掉这些突发请求。但是漏桶算法处理请求的速度是均匀的,此时就导致系统的处理能力被闲置了。也就是无法有效的高效处理突发流量。

令牌桶则是为了处理突发流量下的一种不同的算法。令牌桶算法可以想象存在着一个存储“许可”的桶。系统按照恒定的速率往桶内放置“许可”,许可桶本身存在容量上限,如果系统放置的许可超出了上限,则会被丢弃。而外部的请求进来,每次都要申请足够数量的许可,只有许可申请成功的情况下请求才能被处理。如果请求无法申请到足够的许可,请求或许等待,或者被丢弃。显然,在有突发流量的时候,请求可以一次性消耗完毕桶内所有的令牌。这一特性,使得令牌桶特别适合于处理突发的流量。

在 Sentinel 中,进行流量整型的主要是接口 TrafficShapingController 。该接口定义了方法 canPass 用于判定当前请求是否允许被执行。下面我们就来分析下这个流量整型接口。

代码分析

这个接口的类图如下

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201029014124.png” style=”zoom:50%;” />

先来大致介绍下这个接口的使用流程。

在 FlowSlot 的实现中,其会调用方法FlowRuleChecker#checkFlow来判断当前请求是否允许通过。而该方法内部的逻辑是获取当前系统内所有的 FlowRule 实例,每一个 FlowRule 实例按照规则,系统都会为其初始化一个 TrafficShapingController 实例。使用这个 TrafficShapingController 实例来判断这个请求是否允许被放行。此时就是这个接口发挥作用的时候。这个流程我们还会在后续详细分析,这里先忽略,先关注 TrafficShapingController 的具体实现。如类图所示,这个接口 Sentinel 框架为我们默认提供了四种实现。

DefaultController

默认流量整形控制器。默认流量整型控制器的对超出阈值的流量的处理逻辑是直接拒绝。下面来看下其对于 canPass 方法的实现流程,如图所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201106171751.png” alt=”image-20201106171750850″ style=”zoom: 80%;” />

这边有个流程需要展开说明下,也就是尝试申请未来许可,也就是方法StatisticNode#tryOccupyNext。这个算法直接看代码实现的话会有一些晦涩。在这里我们先通过一个例子来说明其设计思路。

假定我们当前有一个取样大小为 4 ,统计周期为 1S 的滑动窗口。系统允许的 QPS 为 40,这就是说在一个统计周期中,最大记录的许可数不能超过 40 。该滑动窗口当前的情况如下图所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108232149.png” alt=”image-20201108232149571″ style=”zoom:50%;” />

黑色竖线代表当前的时间戳节点,绿色横线代表已经流逝的时间,红色横线代表时间戳所在的取样窗口未来剩余的时间。下方的绿色格子代表取样窗口,中间的数字代表该取样窗口内统计到数字。

从图中可以看出,该滑动窗口内当前已经记录了 30 个许可。如果此时要再申请 30 个许可,就会超出系统的阈值,那么显然是在当前的取样窗口中无法完成的。因此只能像未来还未申请到的取样窗口去请求许可。

要向未来的取样窗口去申请许可,就需要确定,当前的取样窗口失效多少个之后,才能释放出足够的许可。为了计算这个结果,我们临时用另外一个滑动窗口来计算该滑动窗口内的总许可数,如下。

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108232818.png” alt=”image-20201108232818199″ style=”zoom:50%;” />

初始情况下,用于统计的滑动窗口与当前的滑动窗口是一致的,当前已经分配了 30 个许可,显然无法再分配 30 个许可。那么滑动窗口右移一个取样窗口的长度,就会变成下面的情况

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108234401.png” alt=”image-20201108234401413″ style=”zoom:50%;” />

此时滑动窗口内许可的数量是 20 ,还是不够分配。继续右移一个取样窗口的长度,变为如下情况

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201108234440.png” alt=”image-20201108234440597″ style=”zoom:50%;” />

此时滑动窗口的许可总数是 10 ,足够分配 30 个许可了。这就意味着需要等待 2 个取样窗口的时间外加之前取样窗口剩余的时间,也就是红线部分代表的时间,滑动窗口内才会足够的许可数量来满足。

当然,在等待的过程中,其他线程也可能会来申请许可,因此单纯等待是不可取的,当明确时间后,就需要首先将这些未来的许可都提前占据,避免被其他线程获取到或者占据到。

总结来说,申请未来许可可以细分为两个步骤:

  • 从当前时间戳计算出当前滑动窗口的起始点时间戳。声明一个以该时间戳为起始点的滑动窗口,不断向右滑动取样窗口的长度,直到滑动窗口可以满足未来许可的申请数量。通过滑动窗口移动的次数和取样窗口的长度以及当前时间戳在自身取样窗口所谓的位置,可以得到当前线程为获得许可需要等待的时间。
  • 以上面的时间为依据,提前占据未来的许可,避免被其他线程抢夺。

第二个步骤,在 DefaultController 的代码中实现了,也就是申请占据未来许可这段。而第一个步骤,就是方法StatisticNode#tryOccupyNext的实现内容。下面我们来看下代码流程,如下:

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201109011722.png” alt=”image-20201109011722343″ style=”zoom:80%;” />

到这里,DefaultController 的主要流程就分析完了。这是 Sentinel 中的流控默认实现,支持高优先级的请求在允许范围内提前消耗系统未来许可,从而保证高优先请求的优先响应。

当 DefaultController 抛出 PriorityWaitException 异常的时候,处理器槽 StatisticSlot 会捕获这个异常,该异常不会中断请求,而是会让继续执行。只不过统计节点此时只需要新增运行中线程数即可,因为因为访问统计在抛出异常之前的DefaultController.canPass方法中已经完成了。

RateLimiterController

相比于上者,RateLimiterController 的思路则简单的多。RateLimiterController 的流控思路就是排队等待。每次新的请求产生的时候,就计算产生该请求对应的许可需要耗费的时间,该时间加上上次请求的时间点减去当前时间点就得到了本次请求需要等待的时间。如果这个时间小于最大排队时间,则当前线程休眠该时间后处理该请求;否则阻断该请求。

RateLimiterController 的实现并没有非常严格的代码限制,不过通常而言,其实现的效果是所有的请求是被排队后“依次”发生。来看下其canPass方法的实现逻辑,整体流程如下

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201109180308.png” alt=”image-20201109180302012″ style=”zoom: 33%;” />

这个流程并不是一个精确计算的排队实现,不过对于流控而言,过于精确的操作,会对原本的请求有一定的负面影响。因此实现成这样,也是可以理解的。

WarmUpController

算法分析

对于一些系统而言,单纯对于阈值的限制仍然是不够的。一些系统能够承受较高的 QPS ,但是系统的承受能力有明显的周期特性。比如说系统在长期无使用的时候,对外部请求的响应时间会变长。而当访问不停发生的时候,系统的吞吐就会逐渐提高上来,延迟降低,表现为 QPS 升高。这种情况下,我们就需要对系统进行”预热“。也就是在系统刚启动,或者长时间无流量的情况下,将限制阈值压在比较低的范围。如果访问持续发生,按照一定的速度提升 QPS 阈值,直到达到系统的上限。

限流器对系统 QPS 的限制和时间关系如下所示

<img src=”https://markdownpic-1251577930.cos.ap-chengdu.myqcloud.com/20201202183722.png” style=”zoom:50%;” />

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 源码解读五:流量整型算法实现分析求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们