限流则是从用户访问压力的角度来考虑如何应对故障。限流指只允许系统能够承受的访问量进来,超出系统访问能力的请求将被丢弃。
虽然“丢弃”这个词听起来让人不太舒服,但保证一部分请求能够正常响应,总比全部请求都不能响应要好得多。
限流一般都是系统内实现的,常见的限流方式可以分为两类:基于请求限流和基于资源限流。
基于请求限流
基于请求限流指从外部访问的请求角度考虑限流,常见的方式有两种。
第一种是限制总量,也就是限制某个指标的累积上限,常见的是限制当前系统服务的用户总量,例如:某个直播间限制总用户数上限为 100 万,超过 100 万后新的用户无法进入;某个抢购活动商品数量只有 100 个,限制参与抢购的用户上限为 1 万个,1 万以后的用户直接拒绝。
第二种是限制时间量,也就是限制一段时间内某个指标的上限,例如 1 分钟内只允许 10000 个用户访问;每秒请求峰值最高为 10 万。
基于资源限流
基于请求限流是从系统外部考虑的,而基于资源限流是从系统内部考虑的,也就是找到系统内部影响性能的关键资源,对其使用上限进行限制。常见的内部资源包括连接数、文件句柄、线程数和请求队列等。
例如,采用 Netty 来实现服务器,每个进来的请求都先放入一个队列,业务线程再从队列读取请求进行处理,队列长度最大值为 10000,队列满了就拒绝后面的请求;也可以根据 CPU 的负载或者占用率进行限流,当 CPU 的占用率超过 80% 的时候就开始拒绝新的请求。
基于资源限流相比基于请求限流能够更加有效地反映当前系统的压力,但实际设计时也面临两个主要的难点:如何确定关键资源,以及如何确定关键资源的阈值。
限流算法
为了更好地实现前面描述的各种限流方式,通常情况下我们会基于限流算法来设计方案。常见的限流算法有两大类四小类,它们的实现原理和优缺点各不相同,在实际设计的时候需要根据业务场景来选择。
时间窗算法
第一大类是时间窗算法,它会限制一定时间窗口内的请求量或者资源消耗量,根据实现方式又可以细分为“固定时间窗”和“滑动时间窗”。
固定时间窗
原理:统计固定时间周期内的请求量,如果超过限额就会限流。
优点:实现简单
缺点:存在临界点问题,在两个窗口的相邻临界点会存在2个极限峰值,从单个窗口周期看并没有超出限额,也就是没有限流。实际在一个周期内已经超过了限额,系统可能因压力过大二挂掉。

滑动时间窗
原理:把一个统计周期平均分为多个时间段,两个统计周期部分重叠,从而避免短时间内的两个统计点分属不同的时间窗的情况。
优点:比固定窗口限流粒度更细,效果更好。
缺点:实现比固定窗口复杂。

桶算法
用一个虚拟的“桶”来临时存储一些东西。根据桶里面放的东西,又可以细分为“漏桶”和“令牌桶”。
漏桶
原理:将请求放入“桶”(消息队列等),业务处理单元(线程、进程和应用等)从桶里拿请求处理,桶满则丢弃新的请求。
实现点:流入速率不固定,极速匀速流出,桶满则丢弃请求。本质是总量控制,桶大小是关键。
优点:突发大流量时丢弃的请求较少,因为漏桶本身有缓存请求的作用,桶的大小比令牌桶的大。
缺点:桶大小动态调整比较困难,无法精确控制流出速度(业务处理速度)。
适用场景:瞬时高并发流量的场景,比如整点秒杀。

令牌桶
原理:桶中放入的是“令牌”,当系统收到一个请求时,先要到令牌桶里面拿“令牌”,拿到令牌才能进一步处理,拿不到就要丢弃请求。
实现点:令牌生成速度是可控的,桶可以缓存一定数量令牌,可面对一定突发流量;如果令牌不足,即使系统有能力处理,也会丢弃请求。本质是速率控制。
优点:可以动态调整处理速率。
缺点:突发大量流量的时候可能丢弃很多请求,因为令牌桶不能累积太多令牌。实现相对复杂。
适用场景:一种是需要控制访问第三方服务的速度,防止把下游压垮,例如支付宝需要控制访问银行接口的速率;另一种是需要控制自己的处理速度,防止过载。
令牌桶在实际设计的时候,桶大小不能像漏桶那样设计很大,需要根据系统的处理能力来进行仔细的估算。

总结
| 算法 | 原理 | 优点 | 缺点 | 场景 |
|---|---|---|---|---|
| 固定窗口 | 统计一个周期内的请求量 | 实现简单 | 临界点问题 | 普通限流 |
| 滑动窗口 | 一个周期分为多个小窗口 | 限流粒度较细 | 临界点问题,实现稍复杂 | 普通限流 |
| 漏桶 | 桶里是请求,总量控制 | 桶大小可控,可应对突发流量 | 无法精确控制流出速度 | 秒杀 |
| 令牌桶 | 桶里是令牌,请求从桶里拿令牌,速率控制 | 速率可控 | 突发大流量会丢弃许多请求,实现复杂 | 平稳限流,如访问第三方服务 |
文档信息
- 本文作者:yindongxu
- 本文链接:https://iceblow.github.io/2022/03/03/%E9%99%90%E6%B5%81%E7%AE%97%E6%B3%95/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)