小小小幸运 发表于 2024-8-22 06:32:24

【Redis】解析Redisson 限流器源码

https://img-blog.csdnimg.cn/9633f3bb7c3643d0a6989e51c0470ac6.gif#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center
https://img-blog.csdnimg.cn/img_convert/7b0d6ba5dcce6ce6b2e732fdffde6496.gif#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center
一、注解AOP 代码部分提取

https://i-blog.csdnimg.cn/direct/c433a95311874721bfd4948fda85498d.png
// 调用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);
源码分析
源码截图:
https://i-blog.csdnimg.cn/direct/f15ac9daa5994f62b11bb5c46b99618c.png

[*]
分析: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, 'rate', ARGV);"
            + "redis.call('hsetnx', KEYS, 'interval', ARGV);"
            + "return redis.call('hsetnx', KEYS, 'type', ARGV);",
                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, 'rate', ARGV);"
+ "redis.call('hsetnx', KEYS, 'interval', ARGV);"
+ "return redis.call('hsetnx', KEYS, 'type', ARGV);"

--- 解释
这段 Lua 脚本中,通过 redis.call('hsetnx', KEYS, 'rate', ARGV) 等命令,尝试对 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;
    }
}
假如代码写的有标题,欢迎大家品评交流,举行指点!!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【Redis】解析Redisson 限流器源码