Redisson 限流器源码分析

Redisson 限流器源码分析

对上篇文章网友评论给出问题进行解答:redis 的key 是否会过期

可以先阅读上篇文章:

redis + AOP + 自定义注解实现接口限流 - 古渡蓝按 - 博客园 (cnblogs.com)

注解AOP 代码部分提取

Redisson 限流器源码分析

// 调用Reids工具类的rateLimiter 方法  long number = RedisUtils.rateLimiter(combineKey, rateType, count, time); 

redis 工具类

public class RedisUtils {      private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class);      /**      * 限流      *      * @param key          限流key      * @param rateType     限流类型      * @param rate         速率      * @param rateInterval 速率间隔      * @return -1 表示失败      */     public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {               // 获取一个限流器         RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);         // 将限流的配置信息保存在Redis中         rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);         // tryAcquire 用于获取当前可用的许可数         if (rateLimiter.tryAcquire()) {             return rateLimiter.availablePermits();         } else {             return -1L;         }     } }     

解析

rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);

源码分析

源码截图:

Redisson 限流器源码分析
1.
分析:trySetRate 调用 trySetRateAsync 方法

@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.evalWriteNoRetryAsync(getRawName(), 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.singletonList(getRawName()), rate, unit.toMillis(rateInterval), type.ordinal());     } 

逐步分析代码:

  • commandExecutor.evalWriteNoRetryAsync():这里使用了 Redis 的 EVAL 命令,这个命令允许执行 Lua 脚本,而不会受到 Redis 的同步阻塞操作。
  • getRawName():这是获取限流器的名称或标识。
  • RedisCommands.EVAL_BOOLEAN:表示执行 Lua 脚本后期望的返回值类型为 Boolean。

源码lua 脚本解释

-- 源码lua 脚本  "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]);"   --- 解释 这段 Lua 脚本中,通过 redis.call('hsetnx', KEYS[1], 'rate', ARGV[1]) 等命令,尝试对 Redis 的 Hash 数据结构进行设置操作。 首先尝试设置 'rate' 字段为传入的速率值; 然后尝试设置 'interval' 字段为传入的时间间隔值; 最后尝试设置 'type' 字段为传入的类型值。这里使用了 hsetnx 命令来进行设置操作,如果字段已存在,则不会进行设置操作。 
  • Collections.singletonList(getRawName()):将限流器的名称作为参数传递给 Lua 脚本。
  • rate, unit.toMillis(rateInterval), type.ordinal():这三个参数分别是速率、时间间隔以毫秒为单位、以及限流类型

总结:这段代码本身并没有提供设置限流器自动过期的功能。在 Redisson 中,限流器自动过期的功能通常不是默认包含在限流器的设置中。

设置限流器的失效时间

限流器自动过期(是指的是限流这个功能),可以使用expire进行失效时间设置

修改后代码:

/**      * 限流      *      * @param key          限流key      * @param rateType     限流类型      * @param rate         速率      * @param rateInterval 速率间隔      * @param expirationTimeInSeconds 过期时间(秒)      * @param isExpire 是否设置限流器过期      * @return -1 表示失败      */  public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval, long expirationTimeInSeconds,boolean isExpire) {          RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);          rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);          if(isExpire){         // 是否设置过期时间        rateLimiter.expire(expirationTimeInSeconds, TimeUnit.SECONDS);     }     if (rateLimiter.tryAcquire()) {         return rateLimiter.availablePermits();     } else {         return -1L;     } }  

如果代码写的有问题,欢迎大家评论交流,进行指点!!!

也希望大家点个关注哦~~~~~~~~

发表评论

评论已关闭。

相关文章

当前内容话题