软件体系架构阅读笔记十三

3. 限流模式

服务的容量和性能是有限的,在第3章中会介绍如何在架构设计过程中评估服务的最大性能和容量,然而,即使我们在设计阶段考虑到了性能压力的问题,并从设计和部署上解决了这些问题,但是业务量是随着时间的推移而增长的,突然上量对于一个飞速发展的平台来说是很常见的事情。

针对服务突然上量,我们必须有限流机制,限流机制一般会控制访问的并发量,例如每秒允许处理的并发用户数及查询量、请求量等。

有如下几种主流的方法实现限流。

1)计数器

通过原子变量计算单位时间内的访问次数,如果超出某个阈值,则拒绝后续的请求,等到下一个单位时间再重新计数。

在计数器的实现方法中通常定义了一个循环数组(见下图),例如:定义5个元素的环形数组,计数周期为1s,可以记录4s内的访问量,其中有1个元素为当前时间点的标志,通常来说每秒程序都会将前面3s的访问量打印到日志,供统计分析。

 

我们将时间的秒数除以数组元素的个数5,然后取模,映射到环形数组里的数据元素,假如当前时间是1 000 000 002s,那么对应当前时间的环形数组里的第3个元素,下标为2。

此时的数组元素的数据如下图所示。

 

在上图中,当前时间为1 000 000 002s,对应的计数器在第3个元素,下标为2,当前请求是在这个时间周期内的第1个访问请求,程序首先需要对后一个元素即第4个元素,也就是下标为3的元素清零;在1 000 000 002s内,任何一个请求如果发现下标为3的元素不为0,则都会将原子变量3清零,并记录清零的时间。

这时程序可以对第3个元素即下标为2的元素,进行累加并判断是否达到阈值,如果达到阈值,则拒绝请求,否则请求通过;同时,打印本次及之前3秒的数据访问量,打印结果如下。

当前:1次,前1s:302次,前2s:201次,前3s:518次

然而,如果当前秒一直没有请求量,下一秒的计数器始终不能清零,则下一秒的请求到达后要首先清零再使用,并更新清零时间。

在下一秒的请求到达后,若检查到当前秒对应的原子变量计数器不为0,而且最后的清零时间不是上一秒,则先对当前秒的计数器清零,再进行累加操作,这避免发生上一秒无请求的场景,或者上一秒的请求由于线程调度延迟而没有清零下一秒的场景,后面这种场景发生的概率较小。

另外一种实现计数器的简单方法是单独启动一个线程,每隔一定的时间间隔执行对下一秒的原子变量计数器清零操作,这个时间间隔必须小于计数时间间隔。

2)令牌筒

令牌筒是一个流行的实现限流的技术方案,它通过一个线程在单位时间内生产固定数量的令牌,然后把令牌放入队列,每次请求调用需要从桶中拿取一个令牌,拿到令牌后才有资格执行请求调用,否则只能等待拿到令牌再执行,或者直接丢弃。

令牌筒的结构如下图所示。

 

3)信号量

限流类似于生活中的漏洞,无论倒入多少油,下面有漏管的流量是有限的,实际上我们在应用层使用的信号量也可以实现限流。 

4. 失效转移模式

若微服务架构中发生了熔断和限流,则该如何处理被拒绝的请求呢?解决这个问题的模式叫作失效转移模式,通常分为下面几种。

  • 采用快速失败的策略,直接返回使用方错误,让使用方知道发生了问题并自行决定后续处理。
  • 是否有备份服务,如果有备份服务,则迅速切换到备份服务。
  • 失败的服务有可能是某台机器有问题,而不是所有机器有问题,例如OOM问题,在这种情况下适合使用failover策略,采用重试的方法来解决,但是这种方法要求服务提供者的服务实现了幂等性。

 转载博客:https://blog.csdn.net/kwame211/article/details/78015601

原文地址:https://www.cnblogs.com/wei-jing/p/11053092.html