1. 为什么要限流?
主要分为 防止崩溃限流 和 业务限流;
限流方式:
- 单机限流
- 集群限流
- 网关限流
- 自动熔断降级
2. 限流算法
滑动窗口计数器
发送端的流量 受制于 流量接受的 窗口大小;多余流量不能处理;处理完一个请求,窗口滑动一位;
它把时间按一定比例分片,比如,我们的服务 1 分钟 能处理 60个请求,我们可以把 1分钟 分为 60个窗口,每隔1秒,移动一个窗口; 当请求数大于 一个窗口能处理的最大数,阻绝服务;
漏桶算法
把请求流量比作 往水桶 里注水, 以任意的速率流入水,以固定的速率流出水;
因为桶的容积不变,保证了整理的速率;
实现方式: 整个队列,加任务满了后拒绝服务 ,以恒定的速度从队列中去任务;
令牌桶算法
还是一一定的速率取任务,不过任务的新增方式变成了 先去令牌桶里拿令牌,然后加桶;
我们以固定的速率生产令牌,和消费桶,就能达到限流目的;
3. 限流框架
alibab-sentinel
可以实现单机、分布式限流;针对dubbo ,可以做到服务提供方,仅对特定应用限流;
存在问题
1) 限流、规则保存在应用节点的内存中,应用发布重启后就会失效,在生产环境中无法接受;
2)规则下发默认是按照机器节点维度而非应用维度;而正常公司是按集群部署的,这样无法支持集群限流;
3)数据记录是保存在内存中的,Dashboard 数据仅仅保留5分钟,错过后可能无法还原”案发现场“,而且无法看流量趋势;
4)如果介入限流的应用有500个,每个应用5个节点,Dashboard 肯定会成为瓶颈,单机的线程池处理不过来;
redis 限流
redis 实现分布式限流,一般会采用令牌桶的做法;使用lua 脚本解决 INCR() 并发重置令牌桶中令牌数的并发问题;
lua 脚本内容流程图
相关redis命令介绍
incr
expire
springboot 使用适配
思考springboot 接入限流需要适配哪些项呢? 下面我列举了几项;
功能项
实现方案
- ✅使用上基于注解
spring aop 实现
- ✅限流key自定义(比如:基于用户传参)
spring EL表达式取参数名称 对象
- ✅限流后的降级处理
1)抛出异常 2)根据用户自定义方法处理
- ✅限流次数支持动态调整
注解中引入dynamic参数,从redis获取设定限流值
以上功能均已实现: 源码地址