精尽 Redisson 源码分析 —— 限流器 RateLimiter
1. 概述
限流,无论在系统层面,还是在业务层面,使用都非常广泛。例如说:
- 【业务】为了避免恶意的灌水机或者用户,限制每分钟至允许回复 10 个帖子。
- 【系统】为了避免服务系统被大规模调用,超过极限,限制每个调用方只允许每秒调用 100 次。
限流算法,常用的分成四种:
每一种的概念,推荐看看 《计数器、滑动窗口、漏桶、令牌算法比较和伪代码实现》 文章。
计数器
比较简单,每固定单位一个计数器即可实现。
滑动窗口
Redisson 提供的是基于滑动窗口 RateLimiter 的实现。相比计数器的实现,它的起点不是固定的,而是以开始计数的那个时刻开始为一个窗口。
所以,我们可以把计数器理解成一个滑动窗口的特例,以固定单位为一个窗口。
令牌桶算法
《Eureka 源码解析 —— 基于令牌桶算法的 RateLimiter》 ,单机并发场景下的 RateLimiter 实现。
《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.10) 之 RequestRateLimiterGatewayFilterFactory 请求限流》 ,基于 Redis 实现的令牌桶算法的 RateLimiter 实现。
漏桶算法
漏桶算法,一直没搞明白和令牌桶算法的区别。现在的理解是:
- 令牌桶算法,桶里装的是令牌。每次能拿取到令牌,就可以进行访问。并且,令牌会按照速率不断恢复放到令牌桶中直到桶满。
- 漏桶算法,桶里装的是请求。当桶满了,请求就进不来。例如说,Hystrix 使用线程池或者 Semaphore 信号量,只有在请求未满的时候,才可以进行执行。
上面哔哔了非常多的字,只看本文的话,就那一句话:“Redisson 提供的是基于滑动窗口 RateLimiter 的实现。”。
2. 整体一览
在 Redisson 中,提供了四个 RateLimiter 相关的接口,如下图:
正在上传…重新上传取消RateLimiter 接口
- org.redisson.api.RRateLimiterAsync ,定义了异步操作的接口。
- org.redisson.api.RRateLimiter ,继承 RRateLimiterAsync 的基础上,定义了同步操作的接口。
- org.redisson.api.RRateLimiterReactive ,定义基于 Reactor 操作的接口。
- org.redisson.api.RRateLimiterReactive ,定义基于 RxJava 操作的接口。
目前,Redisson 暂时只实现了 RRateLimiterAsync 和 RRateLimiter 接口的方法,即 org.redisson.RedissonRateLimiter 。
RRateLimiterAsync 和 RRateLimiter 定义的接口,差别就在于同步和异步,所以我们就只看看 RRateLimiter 接口。代码如下:
boolean trySetRate(RateType mode, long rate, long rateInterval, RateIntervalUnit rateIntervalUnit); RateLimiterConfig getConfig();boolean tryAcquire(); boolean tryAcquire(long permits); boolean tryAcquire(long timeout, TimeUnit unit); boolean tryAcquire(long permits, long timeout, TimeUnit unit);void acquire(); void acquire(long permits); |
#trySetRate(RateType mode, long rate, long rateInterval, RateIntervalUnit rateIntervalUnit)
方法,设置限流器的配置。#getConfig()
方法,获得限流器的配置。#tryAcquire(...)
方法,尝试在指定时间内,获得指定数量的令牌,并返回是否成功。#acquire(...)
方法,在指定时间内,获得指定数量的令牌,直到成功。
总的来说,一共两类方法,一类是设置或获取配置,一类是获取令牌。下面,我们来逐个方法的源码,来瞅瞅。
3. trySetRate
在 《精尽 Redisson 源码分析 —— 调试环境搭建》 中,我们搭建了一个限流器的示例。在示例的开始,我们会调用 RRateLimiter#trySetRateAsync(RateType type, long rate, long rateInterval, RateIntervalUnit unit)
方法,设置限流器的配置。代码如下:
// RedissonRateLimiter.java@Override public boolean trySetRate(RateType type, long rate, long rateInterval, RateIntervalUnit unit) {return get(trySetRateAsync(type, rate, rateInterval, unit)); }@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()), // keys [分布锁名]rate, unit.toMillis(rateInterval), type.ordinal()); // values [速度、速度单位、限流类型] } |
- 将限流器的配置写入到 Redis 中。这个和我们看到的很多分布式限流器的实现不同,它们只提供获取令牌的功能,而 Redisson 多了持久化配置限流器的配置到 Redis 中,相当于说,Redis 起到了一个配置中心的功能,分布式下的相同限流器(“相同”指的是相同名字的限流器)使用同一的配置。
- 参数
type
:类型是 org.redisson.api.RateType ,限流类型。目前有两种:OVERALL
:相同名字的所有 RateLimiter 实例。PER_CLIENT
:相同 JVM 进程的所有相同名字的所有 RateLimiter 实例。精尽 Redisson 源码分析 —— 限流器 RateLimiter相关推荐
- 精尽 Redisson 源码分析 —— 可重入分布式锁 ReentrantLock
1. 概述 在 Redisson 中,提供了 8 种分布锁的实现,具体我们可以在 <Redisson 文档 -- 分布式锁和同步器> 中看到.绝大数情况下,我们使用可重入锁(Reentra ...
- 精尽 Redisson 源码分析 —— 可靠分布式锁 RedLock
1. 概述 我们来看一个 Redis 主从结构下的示例,Redis 分布式锁是如何失效的: 1.客户端 A 从 Redis Master 获得到锁 anylock . 2.在 Redis Master ...
- 精尽 Dubbo 源码分析 —— API 配置
1. 概述 Dubbo 的配置目前提供了四种配置方式:1. API 配置 2. 属性配置 3. XML 配置 4. 注解配置 2. 配置一览 我们来看看 dubbo-config-api 的项目结构, ...
- 精尽 jasypt-spring-boot 源码分析 3.0.4
1 依赖工具 Maven Git JDK IntelliJ IDEA 2 源码拉取 git clone git://github.com/ulisesbocchio/jasypt-spring-boo ...
- mybatis一个方法执行多条sql_精尽MyBatis源码分析——SQL执行过程之Executor!
MyBatis的SQL执行过程 在前面一系列的文档中,我已经分析了 MyBatis 的基础支持层以及整个的初始化过程,此时 MyBatis 已经处于就绪状态了,等待使用者发号施令了 那么接下来我们来看 ...
- redisson分布式限流[RRateLimiter]源码分析
接下来在讲一讲平时用的比较多的限流模块–RRateLimiter 1.简单使用 public static void main(String[] args) throws InterruptedExc ...
- 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现
概述 我们知道 Spring Boot 能够创建独立的 Spring 应用,内部嵌入 Tomcat 容器(Jetty.Undertow),让我们的 jar 无需放入 Servlet 容器就能直接运行. ...
- 【Android源码】源码分析深度好文+精编内核解析分享
阅读Android源码的好处有很多,比如:可以加深我们对系统的了解:可以参考牛人优雅的代码实现:可以从根本上找出一些bug的原因-我们应该庆幸Android是开源的,所有的功能都可以看到实现,所有的b ...
- 【精】EOS智能合约:system系统合约源码分析
系统合约在链启动阶段就会被部署,是因为系统合约赋予了EOS链资源.命名拍卖.基础数据准备.生产者信息.投票等能力.本篇文章将会从源码角度详细研究system合约. 关键字:EOS,eosio.syst ...
最新文章
- flex 单独一行_Flex网页布局一CSS弹性伸缩盒子语法教程
- 燕山大学计算机专业研究生怎么样,求助大家!重庆邮电大学计算机专业的研究生值得一读吗?...
- JS图片放大查看效果!
- 不止代码:保留道路(ybtoj 最小生成树)
- 循环自相关函数和谱相关密度(二)——实信号、复信号模型下的BPSK信号循环谱推导
- 管道符和作业控制 shell变量 环境变量配置文件
- SpringCloud Gateway 服务网关,断言
- Java坦克大战(四)
- js读取txt文件中的内容
- 权重计算方法一:层次分析法(AHP)
- 第六次毕业设计任务书
- Go语法·类型选择(type switch)
- Pycahrm pip instell parsel时出现错误 error: Unable to find vcvarsall.bat解决过程
- u盘UEFI模式安装Windows10和ubuntu18.04双系统
- vue-router路由模式有几种?
- pytorch的paramter
- 码农之路从入门到放弃之:计算机基础知识
- 《Java 技术体系》之一:Java 技术体系概览
- 数据库系统概论第五版(理论总结)
- 电脑报网站使用盗版软件?
热门文章
- 精尽 Redisson 源码分析 —— 可重入分布式锁 ReentrantLock