高可用架构-限流如何实现

What is 限流/h2>

限流顾名思义,限制流量或者说叫流量管制。

很形象的比喻如老式电闸都安装了保险丝,一旦有人使用超大功率的设备,保险丝就会烧断以保护各个电器不被强电流给烧坏。


Why use 限流/h2>

理论上一个完整的对外提供服务的系统架构在设计初期,就要基于上游流量流速高峰期时间点峰值 qps,还有自身系统的负载能力,评估系统的吞吐量,并且进行入口流量的管制。

当超出限流阈值时,系统可以采取拒绝服务,排队或者引流等机制, 保证自身一直在健康的负载下。

如果系统没有限流策略,对于突发性的超自身负载的流量,系统只能被动的无奈接受,系统内各个子服务逐渐解体,最后服务整体雪崩。

高可用架构-限流如何实现

了解 lua-resty-lock: https://github.com/openresty/lua-resty-lock

Nginx.conf

应用层

应用层常见通过业务代码实现,基于 Redis 计数, 通过 lua script 保证 redis 执行原子性.

单机限流

单兵作战,自生自灭,我不倒集群不倒。不依赖存储中间件,基于 local cache 就可以实现简单的本地计数限流,宏观角度观察,只要网关层负载均衡服务高可用,每个节点流量差别不大,只需要关心单个节点的流量管控就可以。


以上是限流粒度分类,下面说说具体的限流算法模型。


限流模型

以上 Demo 都是基于简单的固定时间窗口模型实现限流,但是当出现临界点瞬间大流量冲击,。

常用的模型分类有两种:

  • 时间模型
  • 桶模型

时间模型

时间模型分两种:

  • 固定窗口模型
  • 滑动窗口模型

固定时间模型

高可用架构-限流如何实现

如图(图片来源网络),在 900ms 和 1100ms 都出现 1000QPS 并发,虽然单个窗口内是符合限流要求,但是实际上临界点处的 QPS 已经打到 2000,服务过载。

滑动时间模型

高可用架构-限流如何实现

算法实现方式有两种:

  • Ticker
    定义一个 Ticker,持续生成令牌并导入桶中。这样问题是会极大的消耗系统资源。如果基于某一维度进行限流,会创建多桶,对应多 Ticker,资源消耗很可怕。
  • Inert Fill
    惰性填充,定义一个 inert fill 函数。该函数会在每次获取令牌之前调用,其实现思路为,若当前时间晚于 lastAccessTime,则计算该段时间内可以生成多少令牌,将生成的令牌加入令牌桶中并更新数据。这样一来,只需要在获取令牌时计算一次即可。

桶内令牌数计数方式

桶内令牌数 = 剩余的令牌数 + (本次取令牌的时刻-上一次取令牌的时刻)/放置令牌的时间间隔 * 每次放置的令牌数

常用令牌桶如: github.com/juju/ratelimit

多种填充令牌方式:

默认令牌桶,fillInterval 每过多间向桶令牌,capacity 是桶的容量,超过桶容量的部分会被直接丢弃。

和默认方式一样,唯一不同是每次填充的令牌数是 quantum,而不是 1 个。

按照使用方定义的,每秒钟填充令牌数。比如 capacity 是 100,rate 是 0.1,那么每秒会填充 10 个令牌。

多种领取令牌方式:

如下,我简单实现了一个极简的令牌桶, 速率默认为 QPS 。

TokenBucket Demo

Struct 结构
Inert Fill

桶内令牌数 = 剩余的令牌数**** + (本次取令牌的时刻**** – 上一次取令牌的时刻**) / 放置令牌的时间间隔速率为 qps,所以此处是** * 每次放置的令牌数****


漏桶模型

漏桶算法思路很简单,如下图(图片来源网络),水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

简单的说: 调用方只能严格按照预定的间隔顺序进行消费调用。

Ref: https://en.wikipedia.org/wiki/Leaky_bucket

高可用架构-限流如何实现

常用漏桶: https://github.com/uber-go/ratelimit

对于很多应用场景来说,除了要求能够限制流量的平均传输速率外,还要求允许某种程度的突发传输。

传统的 Leaky Bucket,关键点在于漏桶始终按照固定的速率运行,但是它并不能很好的处理有大量突发请求的场景。

对于这种情况,uber-go 对 Leaky Bucket 做了一些改良,引入了最大松弛量 (maxSlack) 的概念。

当请求间隔时间小于固定的速率时,可以把间隔比较长的请求多余出来的时间 buffer,匀给后面的使用,保证每秒请求数。如果间隔时间远远超出固定速率,那会给后续请求增加超大的 buffer,以至于即使后面大量请求瞬时到达,也无法抵消完这个时间,那这样就失去了限流的意义。所以 maxSlack 会限制这个 buffer 上限。

LeakyBucket Demo

如下,实现了一个极简的非阻塞漏桶。

Struct 结构
无松弛量实现

来源:晓旭z

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年5月12日
下一篇 2021年5月12日

相关推荐