限流器

限流器的主要作用是控制流量,保护系统不会在过载情况下出现问题。

比如在某些场景下,当并发访问量陡增时,可能会给系统带来毁灭性打击,继而引起系统雪崩,导致服务不可用。比如在一些秒杀,抢票的场景,在一些评论、下单的场景,我们可以根据每个场景的特点来定制适合的限流方案,即使出现高并发的时候,也能正常服务或有损服务,不至于服务挂掉。

一般的应用场景有:

  1. 防止恶意请求流量

  2. 防止恶意攻击

  3. 防止流量超出系统峰值

限流的一般方式有:

  1. 限制总并发数(如数据库连接池、线程池等)

  2. 限制瞬时并发数(如Nginx 的 limit_conn 等)

  3. 限制时间窗口内的平均速率(如Guava 的 RateLimiter、Nginx 的 limit_req 等)

  4. 限制远程接口调用速率

  5. 限制 MQ 的消费速率

  6. 限制每秒平均速率

当然限流不是目的,一旦达到了限流的阈值,就会触发相应的限流行为。比如:

  1. 拒绝服务

  2. 服务降级

  3. 特权请求

  4. 延时处理

  5. 弹性伸缩

限流器算法

限流有一些常用的限流算法,也有很多类库封装了这些算法。

  • 计数法

算法思想:维护一个计数器,当一个请求来时,就做加1操作,当一个请求处理完成时,就做减1操作;如果这个 Counter 大于某个数了(我们设定的限流阈值),那么就开始拒绝请求以保护系统的负载了。

这个算法简单粗暴。

但是这种方法存在缺点:不能均衡限流,在一个单位时间的末尾和下一个单位时间的开始,很可能会有两个访问的峰值,导致系统崩溃。

  • 滑动窗口法

  • 令牌桶法

令牌桶算法的详细描述如下:

  1. 令牌以固定的速率添加到令牌桶中,假设限流的速率是 r/ 秒,则令牌每 1/r 秒会添加一个;

  2. 假设令牌桶的容量是 b ,如果令牌桶已满,则新的令牌会被丢弃;

  3. 请求能够通过限流器的前提是令牌桶中有令牌。

  4. 漏桶法

漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率。

一般来说,这个“漏斗”是用一个队列来实现的,当请求过多时,队列就会开始积压请求,如果队列满了,就会开拒绝请求。很多系统都有这样的设计,比如 TCP。当请求的数量过多时,就会有一个 sync backlog 的队列来缓冲请求,或是 TCP 的滑动窗口也是用于流控的队列。漏斗算法其实就是在队列请求中加上一个限流器,来让 Processor 以一个均匀的速度处理请求。

最后更新于