关键词总结:限流的策略、限流的实现方式、基于响应时间的动态限流、限流的设计要点
限流的策略
限流,是对并发访问进行限速,保护系统不会在过载的情况下出现问题
一般来说,触发的限流行为如下
拒绝服务
一般的做法,是当流量暴增的时候,将同一时间内发起请求数最多的客户端请求全部丢弃。这种方法可以抵挡住恶意发起的高并发请求。
服务降级
关闭或是把后端服务做降级处理,腾出资源处理更多的请求。
降级的方式有:
- 停掉非重要服务:把 CPU、内存或是数据的资源让给更重要的功能
- 返回部分数据:不再返回全量数据,只返回部分数据,减少数据的 SQL Join 操作
特权请求
把有限的资源分给重要的用户,比如:分给权利更高的 VIP 用户。。在多租户系统下,限流的时候应该保大客户。
延时处理
一般会使用一个队列来缓冲大量的请求,队列如果满了,那么就只能拒绝用户了。
弹性伸缩
动用自动化运维的方式对相应的服务做自动化的伸缩。需要一个应用性能的监控系统,感知最繁忙的Top服务,并通过自动化的发布、部署和服务注册的运维系统去伸缩它们。如果是数据库的压力,那么弹性伸缩应用是没什么用的
限流的实现方式
计数器方式
维护一个计数器 Counter,当一个请求来时,就做加一操作,当一个请求处理完后就做减一操作,来实现最简单的限流算法。这个 Counter 大于某个数了(设定的限流阈值),那么就开始拒绝请求以保护系统的负载了。
队列算法
请求的速度可以是波动的,而处理的速度则是非常均速的,有点像一个 FIFO 的算法。
优先级的队列
在上面这个 FIFO 的队列上加上优先级,处理时先处理高优先级的队列,然后再处理低优先级的队列。只有高优先级的队列被处理完成后,才会处理低优先级的队列。
有个问题是: 如果高优先级的队列一直未处理完,那么低优先级的队列的请求一直得不到处理。使用带权重的队列可以处理
带权重的队列
分配不同比例的处理时间到不同的队列上。如下图所示,有三个队列的权重分布是 3:2:1。
队列算法需要用队列长度来控制流量,在配置上比较难操作。队列过长,队列还未满时后端已经受不住压力挂掉了。
漏斗算法 Leaky Bucket
Wikipedia 的相关词条: Leaky Bucket
一般来说,这个“漏斗”是用一个队列来实现的,漏斗算法其实就是在队列请求中加上一个限流器,强行限制数据的传输速率。
令牌桶算法 Token Bucket
令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,
系统会按恒定时间间隔往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.在流量小的时候“攒钱”,流量大的时候,可以快速处理。
基于响应时间的动态限流
上面的算法有个不好的地方,就是需要设置一个确定的限流值。而这个阈值不是那么好确定的,需要做性能测试,找到系统最大的性能值。很多时候并不知道这个限流值,或是很难给出一个合适的值。
很难设定限流值的原因
- 数据库方面:很多服务会依赖于数据库,不同的用户请求,会对不同的数据集进行操作,即时相同请求数据集也会不一样。并且数据库的数据是在不断变化的,可能会随着数据量增加导致性能变差。
- API方面: 不同的 API 有不同的性能,如果要对每一个 API 配置不同的限流值,这点太难配置,也很难管理。
- 平台方面:服务都是能自动化伸缩的,不同大小的集群的性能也不一样,自动化伸缩后要求要动态调整阈值,这很难做到。
基于上述这些原因,限流的值是很难被静态地设置成恒定的一个值。使用一种动态限流的方式,不再设定一个特定的流控值,而是能够动态地感知系统的压力来自动化地限流。这方面设计的典范是 TCP 协议的拥塞控制的算法(可参看 https://blog.csdn.net/leacock1991/article/details/100612264 、 https://coolshell.cn/articles/11609.html) 。
限流的设计要点
限流的目的
- 在指定的速度下要保持一个范围内的响应时间以及可用性;
- 确保多租户间的情况下,整体系统的资源不会被某个租户所耗尽;
- 为了应对突发的流量;
- 在尽可能节省成本的情况下将资源的利用率最大化。
需要考虑的地方
- 在架构的早期一开始就做好限流的准备;
- 限流模块性能必须好,对流量感知灵敏;
- 允许人工手动干预限流操作;
- 限流发生时需要被监控,有个监控事件通知;
- 限流发生时,对于拒掉的请求需返回定制限流产生的错误码,使客户端可见从而调整发送速度;
- 限流应该让后端感知,告诉后端服务限流的级别,以便后端服务可以根据这个标识决定是否做降级。。
参考资料:
左耳听风(极客时间)链接:
http://gk.link/a/10f5D
GitHub链接:
https://github.com/lichangke/LeetCode
CSDN首页:
https://me.csdn.net/leacock1991
欢迎大家来一起交流学习