springboot|业内限流常用技术方案 redis +lua sentinel guava
1:背景
在高并发业务场景下,常用的三板斧:"熔断、降级和限流"。接下来重点梳理一下常用的限流算法的几种实现方式。
相关测试代码见:https://gitee.com/javadev/data-x2:常用解决方案
【springboot|业内限流常用技术方案 redis +lua sentinel guava】相关测试通过 ab -n 20 -c 15 http://localhost:8805/limiting/tpt
1:漏桶算法
漏桶算法思路很简单:我们把水比作是请求,漏桶比作是系统处理能力极限,水先进入到漏桶里,漏桶里的水按一定速率流出,当流出的速率小于流入的速率时,由于漏桶容量有限,后续进入的水直接溢出(拒绝请求),以此实现限流。
2:令牌桶算法
令牌桶算法的原理也比较简单,系统会维护一个令牌(token)桶,以一个恒定的速度往桶里放入令牌(token),这时如果有请求进来想要被处理,则需要先从桶里获取一个令牌(token),当桶里没有令牌(token)可取时,则该请求将被拒绝服务。令牌桶算法通过控制桶的容量、发放令牌的速率,来达到对请求的限制。
com.google.guava
guava
30.1.1-jre
static RateLimiter rateLimiter = RateLimiter.create(10);
if(!rateLimiter.tryAcquire()){
String str = "guavalimiting 我被限流了啊 ,参数=" +name +"," + LocalDateTime.now();
logger.error(str);
}
3:redis& lua (滑动窗口限流)
Lua脚本和 MySQL数据库的存储过程比较相似,他们执行一组命令,所有命令的执行要么全部成功或者失败,以此达到原子性。也可以把Lua脚本理解为,一段具有业务逻辑的代码块。
-- 获取调用脚本时传入的第一个key值(用作限流的 key)local c
c = redis.call('get',KEYS[1])// 调用不超过最大值,则直接返回
if c and tonumber(c) > tonumber(ARGV[1]) then
return c;
end
// 执行计算器自加
c = redis.call('incr',KEYS[1])
if tonumber(c) == 1 then// 从第一次调用开始限流,设置对应键值的过期
redis.call('expire',KEYS[1],ARGV[2])
end
return c;
KEYS[1] 用来表示在redis 中用作键值的参数占位,主要用來传递在redis 中用作keyz值的参数。ARGV[1] 用来表示在redis 中用作参数的占位,主要用来传递在redis中用做 value值的参数。
4:sentinel限流(滑动窗口限流)
sentinel管控台结合@SentinelResource注解来实现服务限流以及熔断降级功能。
blockHandler只负责sentinel控制台配置违规,fallback只负责业务异常.自定义的限流降级方法参数必须带上BolckException,否则找不到定义的方法
blockHandlerClass限流降级处理类配置,单个fallback熔断降级处理方法配置。
字段名称 |
字段解释 |
resource |
资源名,即限流规则的作用对象 |
limitApp |
流控针对的调用来源,若为 default 则不区分调用来源 |
grade |
限流阈值类型(QPS 或并发线程数);0代表根据并发数量来限流,1代表根据QPS来进行流量控制 |
count |
限流阈值 |
strategy |
调用关系限流策略 |
sentinel 如果需要引入sentinel-dashboard,则需要通过引入spring-cloud-starter-alibaba-sentinel
3: 总结
限流常在网关这一层做,比如Nginx、Openresty、Kong、Zuul、Spring Cloud Gateway等,而像spring cloud - gateway网关限流底层实现原理,就是基于Redis + Lua,通过内置Lua限流脚本的方式。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- Guava|Guava RateLimiter与限流算法
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- springboot使用redis缓存
- springboot整合数据库连接池-->druid
- SpringBoot中YAML语法及几个注意点说明
- springboot结合redis实现搜索栏热搜功能及文字过滤
- springboot中.yml文件的值无法读取的问题及解决
- SpringBoot整合MongoDB完整实例代码