• Redisson 限流器源码分析


    Redisson 限流器源码分析

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

    可以先阅读上篇文章:

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

    注解AOP 代码部分提取

    // 调用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);

    源码分析

    源码截图:


    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 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;
        }
    }
    
    

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

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

  • 相关阅读:
    C语言:指针的关系运算
    智慧综合体信息化智能化解决方案
    C++STL的迭代器(iterator)
    Chrome内存追踪
    【项目经验】:elementui表格中数字汉字排序问题及字符串方法localeCompare()
    android开发布局知识
    git stash命令的用法
    Educational Codeforces Round 133 (Rated for Div. 2)(CD题解)
    【ACWing 算法基础】模拟散列表
    216. 组合总和 III
  • 原文地址:https://www.cnblogs.com/blbl-blog/p/18231765