分布式系统学习:16 弹力设计篇:限流设计

关键词总结:限流的策略、限流的实现方式、基于响应时间的动态限流、限流的设计要点

限流的策略

限流,是对并发访问进行限速,保护系统不会在过载的情况下出现问题

一般来说,触发的限流行为如下

拒绝服务

一般的做法,是当流量暴增的时候,将同一时间内发起请求数最多的客户端请求全部丢弃。这种方法可以抵挡住恶意发起的高并发请求。

服务降级

关闭或是把后端服务做降级处理,腾出资源处理更多的请求。

降级的方式有:

  • 停掉非重要服务:把 CPU、内存或是数据的资源让给更重要的功能
  • 返回部分数据:不再返回全量数据,只返回部分数据,减少数据的 SQL Join 操作

特权请求

把有限的资源分给重要的用户,比如:分给权利更高的 VIP 用户。。在多租户系统下,限流的时候应该保大客户。

延时处理

一般会使用一个队列来缓冲大量的请求,队列如果满了,那么就只能拒绝用户了。

弹性伸缩

动用自动化运维的方式对相应的服务做自动化的伸缩。需要一个应用性能的监控系统,感知最繁忙的Top服务,并通过自动化的发布、部署和服务注册的运维系统去伸缩它们。如果是数据库的压力,那么弹性伸缩应用是没什么用的

限流的实现方式

计数器方式

维护一个计数器 Counter,当一个请求来时,就做加一操作,当一个请求处理完后就做减一操作,来实现最简单的限流算法。这个 Counter 大于某个数了(设定的限流阈值),那么就开始拒绝请求以保护系统的负载了。

队列算法

请求的速度可以是波动的,而处理的速度则是非常均速的,有点像一个 FIFO 的算法。

分布式系统学习:16 弹力设计篇:限流设计_第1张图片

优先级的队列

在上面这个 FIFO 的队列上加上优先级,处理时先处理高优先级的队列,然后再处理低优先级的队列。只有高优先级的队列被处理完成后,才会处理低优先级的队列。

分布式系统学习:16 弹力设计篇:限流设计_第2张图片
有个问题是: 如果高优先级的队列一直未处理完,那么低优先级的队列的请求一直得不到处理。使用带权重的队列可以处理

带权重的队列

分配不同比例的处理时间到不同的队列上。如下图所示,有三个队列的权重分布是 3:2:1。

分布式系统学习:16 弹力设计篇:限流设计_第3张图片

队列算法需要用队列长度来控制流量,在配置上比较难操作。队列过长,队列还未满时后端已经受不住压力挂掉了。

漏斗算法 Leaky Bucket

可参看
限流算法之漏桶算法、令牌桶算法

Wikipedia 的相关词条: Leaky Bucket

分布式系统学习:16 弹力设计篇:限流设计_第4张图片

一般来说,这个“漏斗”是用一个队列来实现的,漏斗算法其实就是在队列请求中加上一个限流器,强行限制数据的传输速率。

令牌桶算法 Token Bucket

可参看
限流算法之漏桶算法、令牌桶算法

分布式系统学习:16 弹力设计篇:限流设计_第5张图片

令牌桶算法(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
欢迎大家来一起交流学习

你可能感兴趣的:(分布式学习,分布式)