当前位置:网站首页>The use and principle of distributed current limiting reduction RRateLimiter
The use and principle of distributed current limiting reduction RRateLimiter
2022-07-30 15:06:00 【Java Notes Shrimp】
点击关注公众号,利用碎片时间学习
前提
最近公司在做有需求在做分布式限流,调研的限流框架大概有
1、spring cloud gateway集成redis限流,但属于网关层限流
2、阿里Sentinel,功能强大、带监控平台
3、srping cloud hystrix,属于接口层限流,提供线程池与信号量两种方式
4、其他:redission、手撸代码
实际需求情况属于业务端限流,redission更加方便,使用更加灵活,下面介绍下redission分布式限流如何使用及原理:
一、使用
使用很简单、如下
// 1、 声明一个限流器
RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
// 2、 设置速率,5秒中产生3个令牌
rateLimiter.trySetRate(RateType.OVERALL, 3, 5, RateIntervalUnit.SECONDS);
// 3、试图获取一个令牌,获取到返回true
rateLimiter.tryAcquire(1)
二、原理
1、getRateLimiter
// 声明一个限流器 名称 叫key
redissonClient.getRateLimiter(key)
2、trySetRate
trySetRate方法跟进去底层实现如下:
@Override
public RFuture<Boolean> trySetRateAsync(RateType type, long rate, long rateInterval, RateIntervalUnit unit) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"redis.call('hsetnx', KEYS[1], 'rate', ARGV[1]);"
+ "redis.call('hsetnx', KEYS[1], 'interval', ARGV[2]);"
+ "return redis.call('hsetnx', KEYS[1], 'type', ARGV[3]);",
Collections.<Object>singletonList(getName()), rate, unit.toMillis(rateInterval), type.ordinal());
}
举个例子,更容易理解:
比如下面这段代码,5秒中产生3个令牌,并且所有实例共享(RateType.OVERALL
所有实例共享、RateType.CLIENT
单实例端共享)
trySetRate(RateType.OVERALL, 3, 5, RateIntervalUnit.SECONDS);
那么redis中就会设置3个参数:
hsetnx,key,rate,3
hsetnx,key,interval,5
hsetnx,key,type,0
接着看tryAcquire(1)
方法:底层源码如下
private <T> RFuture<T> tryAcquireAsync(RedisCommand<T> command, Long value) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
"local rate = redis.call('hget', KEYS[1], 'rate');" //1
+ "local interval = redis.call('hget', KEYS[1], 'interval');" //2
+ "local type = redis.call('hget', KEYS[1], 'type');" //3
+ "assert(rate ~= false and interval ~= false and type ~= false, 'RateLimiter is not initialized')" //4
+ "local valueName = KEYS[2];" //5
+ "if type == 1 then "
+ "valueName = KEYS[3];" //6
+ "end;"
+ "local currentValue = redis.call('get', valueName); " //7
+ "if currentValue ~= false then "
+ "if tonumber(currentValue) < tonumber(ARGV[1]) then " //8
+ "return redis.call('pttl', valueName); "
+ "else "
+ "redis.call('decrby', valueName, ARGV[1]); " //9
+ "return nil; "
+ "end; "
+ "else " //10
+ "redis.call('set', valueName, rate, 'px', interval); "
+ "redis.call('decrby', valueName, ARGV[1]); "
+ "return nil; "
+ "end;",
Arrays.<Object>asList(getName(), getValueName(), getClientValueName()),
value, commandExecutor.getConnectionManager().getId().toString());
}
第1、2、3备注行是获取上一步set的3个值:rate、interval、type
,如果这3个值没有设置,直接返回rateLimiter没有被初始化.
第5备注行声明一个变量叫valueName
值为KEYS[2],KEYS[2]
对应的值是getValueName()
方法,getValueName()
返回的就是上面第一步getRateLimiter
我们设置的key;如果type=1,表示全局共享,那么valueName
的值改为取KEYS[3]
,KEYS[3]
对应的值为getClientValueName()
,查看getClientValueName()
源码:
String getClientValueName() {
return suffixName(getValueName(), commandExecutor.getConnectionManager().getId().toString());
}
ConnectionManager().getId()
如下:
public interface ConnectionManager {
UUID getId();
省略...
}
这个getId()是每个客户端初始化的时候生成的UUID,即每个客户端的getId是唯一的,这也就验证了trySetRate
方法中RateType.ALL
与RateType.PER_CLIENT
的作用.
接着看第7标准行,获取
valueName
对应的值currentValue
;首次获取肯定为空,那么看第10标准行else的逻辑set valueName 3 px 5
,设置key=valueName value=3 过期时间为5秒decrby valueName 1
,将上面valueName的值减1那么如果第二次访问,第7标注行返回的值存在,将会走第8标注行,紧接着走如下判断
如果当前valueName的值也就是3,小于要获得的令牌数量(
tryAcquire
方法中的入参),那么说明当前时间内(key的有效期5秒内),令牌的数量已经被用完,返回pttl(key的剩余过期时间);反之说明桶中有足够的令牌,获取之后将会把桶中的令牌数量减1,至此结束.
总结
redission
分布式限流采用令牌桶思想和固定时间窗口,trySetRate
方法设置桶的大小,利用redis key
过期机制达到时间窗口目的,控制固定时间窗口内允许通过的请求量.
来源:blog.csdn.net/promisessh/article
/details/112767743
推荐:
最全的java面试题库
PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里.点“在看”支持我们吧!
边栏推荐
- ToDesk版本更新,引入RTC传输技术,是否早以替代向日葵远程控制?
- ROS 导航
- 分布式限流 redission RRateLimiter 的使用及原理
- 元宇宙邮局AI航天主题系列数字藏品 将于7月30日10:00点上线“元邮数藏”
- MySQL客户端工具的使用与MySQL SQL语句
- 基于FPGA的DDS任意波形输出
- Eclipse connects to SQL server database "recommended collection"
- Digital signal processing course lab report (what foundation is needed for digital signal processing)
- Eight years of testing experience, why was the leader criticized: the test documents you wrote are not as good as those of fresh graduates
- 闭包和装饰器
猜你喜欢
ToDesk版本更新,引入RTC传输技术,是否早以替代向日葵远程控制?
Flink optimization
DocuWare 文件管理与工作流程自动化案例研究——DocuWare 工作流程功能使在家工作的员工能够保持沟通和高效工作,支持混合环境
智能合约安全——私有数据访问
Container sorting case
canal scrape data
Application of time series database in the field of ship risk management
JUC常见的线程池源码学习 02 ( ThreadPoolExecutor 线程池 )
Teach you how to write an eye-catching software testing resume, if you don't receive an interview invitation, I will lose
跳槽前,把自己弄成卷王
随机推荐
基于FPGA的DDS任意波形输出
ESP32 反复重启问题 Arduino屏蔽断电探测器
Normal and escaped strings for postgresql
Web3创始人和建设者必备指南:如何构建适合的社区?
3年软件测试经验面试要求月薪22K,明显感觉他背了很多面试题...
国内数字藏品的乱象与未来
Allure Advanced - Dynamically Generate Report Content
5. DOM
The use of ccs software (app software that makes money reliably)
The highest level of wiring in the computer room, the beauty is suffocating
canal抓取数据
浅析显卡市场的未来走向:现在可以抄底了吗?
2022年,目前大环境下还适合转行软件测试吗?
redis6.0 源码学习(五)ziplist
这个编辑器居然号称快如闪电!
泡沫褪去,DeFi还剩下什么
Teach you how to write an eye-catching software testing resume, if you don't receive an interview invitation, I will lose
Androd 跳转到google应用市场
English语法_不定代词 - both / either / neither
Digital signal processing course lab report (what foundation is needed for digital signal processing)