当前位置:网站首页>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:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里.点“在看”支持我们吧!边栏推荐
- Allure Advanced - Dynamically Generate Report Content
- 关于String的一些思考
- The highest level of wiring in the computer room, the beauty is suffocating
- 浅析显卡市场的未来走向:现在可以抄底了吗?
- 有关收集箱的改进建议
- 71页全域旅游综合整体解决方案2021 ppt
- Before quitting, make yourself a roll king
- What is the relationship between the construction of smart cities and 5G technology in the new era
- A new generation of open source free terminal tools, so cool
- Teach you how to write an eye-catching software testing resume, if you don't receive an interview invitation, I will lose
猜你喜欢

MongoDB starts an error Process: 29784 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=14)

canal scrape data

桌面软件开发框架大赏

跳槽前,把自己弄成卷王

Interface automation framework, lm-easytest beta version released, use it quickly~

Container sorting case

DDS Arbitrary Waveform Output Based on FPGA

吃透Chisel语言.29.Chisel进阶之通信状态机(一)——通信状态机:以闪光灯为例

业内人士真心话:只会测试没有前途的,我慌了......

Flask框架——Sijax
随机推荐
从实例来看DAO:权力分散的伟大尝试
双碳目标下:农田温室气体排放模拟
机器学习在竞赛和工业界应用区别
The website adds a live 2d kanban girl that can dress up and interact
Chapter6 : Has Artificial Intelligence Impacted Drug Discovery?
ESP32 反复重启问题 Arduino屏蔽断电探测器
一文读懂网络效应对Web3的重要意义
Flink optimization
What is the relationship between the construction of smart cities and 5G technology in the new era
Understand the Chisel language. 29. Chisel advanced communication state machine (1) - communication state machine: take the flash as an example
去腾讯面试,直接让人出门左拐 :幂等性都不知道!
Application of time series database in the field of ship risk management
自动化办公|办公软件和亿图脑图MindMaster快捷键
Why do software testing have to learn automation?Talk about the value of automated testing in my eyes
智能合约安全——私有数据访问
业内人士真心话:只会测试没有前途的,我慌了......
华为无线设备Mesh配置命令
JVM性能调优
华为7年经验的软件测试总监,给所有想转行学软件测试的朋友几点建议
1700. 无法吃午餐的学生数量