# 限流器

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

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

一般的应用场景有：

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

![漏桶算法](https://static001.geekbang.org/resource/image/d4/a0/d4b8b6ceb8de4400dfc97f3ff0feeaa0.png)

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