业内限流常用技术方案 redis +lua sentinel guava

1:背景


在高并发业务场景下,常用的三板斧:"熔断、降级和限流"。接下来重点梳理一下常用的限流算法的几种实现方式。

相关测试代码见:https://gitee.com/javadev/data-x 

相关测试通过 ab -n 20 -c 15 http://localhost:8805/limiting/tpt

2:常用解决方案


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限流脚本的方式。

你可能感兴趣的:(springboot,限流,redis,lua,java,spring)