服务高可用--限流

1,111 阅读2分钟

1. 为什么要限流?

主要分为 防止崩溃限流 和 业务限流;

限流方式:

  • 单机限流
  • 集群限流
  • 网关限流
  • 自动熔断降级

2. 限流算法

滑动窗口计数器

发送端的流量 受制于 流量接受的 窗口大小;多余流量不能处理;处理完一个请求,窗口滑动一位;

它把时间按一定比例分片,比如,我们的服务 1 分钟 能处理 60个请求,我们可以把 1分钟 分为 60个窗口,每隔1秒,移动一个窗口; 当请求数大于 一个窗口能处理的最大数,阻绝服务;

image.png

漏桶算法

把请求流量比作 往水桶 里注水, 以任意的速率流入水,以固定的速率流出水;

因为桶的容积不变,保证了整理的速率;

实现方式: 整个队列,加任务满了后拒绝服务 ,以恒定的速度从队列中去任务;

image.png

令牌桶算法

还是一一定的速率取任务,不过任务的新增方式变成了 先去令牌桶里拿令牌,然后加桶;

我们以固定的速率生产令牌,和消费桶,就能达到限流目的;

image.png

3. 限流框架

alibab-sentinel

可以实现单机、分布式限流;针对dubbo ,可以做到服务提供方,仅对特定应用限流;

存在问题

1) 限流、规则保存在应用节点的内存中,应用发布重启后就会失效,在生产环境中无法接受;

2)规则下发默认是按照机器节点维度而非应用维度;而正常公司是按集群部署的,这样无法支持集群限流;

3)数据记录是保存在内存中的,Dashboard 数据仅仅保留5分钟,错过后可能无法还原”案发现场“,而且无法看流量趋势;

4)如果介入限流的应用有500个,每个应用5个节点,Dashboard 肯定会成为瓶颈,单机的线程池处理不过来;

redis 限流

image.png

redis 实现分布式限流,一般会采用令牌桶的做法;使用lua 脚本解决 INCR() 并发重置令牌桶中令牌数的并发问题;

lua 脚本内容流程图

相关redis命令介绍

incr

image.png

expire

image.png

springboot 使用适配

思考springboot 接入限流需要适配哪些项呢? 下面我列举了几项;

功能项

实现方案

  • ✅使用上基于注解

spring aop 实现

  • ✅限流key自定义(比如:基于用户传参)

spring EL表达式取参数名称 对象

  • ✅限流后的降级处理

1)抛出异常 2)根据用户自定义方法处理

  • ✅限流次数支持动态调整

注解中引入dynamic参数,从redis获取设定限流值

以上功能均已实现: 源码地址

参见

API 调用次数限制实现