常用lua 脚本(操作redis)

这里记录一下工作中常用的lua脚本
主要是用来操作redis,保证多个命令原子性

分布式锁

主要是用来保证同一个资源在多个服务中也能保证唯一性的操作
这里加锁主要是利用setnx 命令,保证唯一key只能被一个服务设置成功,并且为了防止出现不能释放锁的问题,所以设置一个过期时间,当然如果redis版本比较的高的话,一个命令也能支持了
解锁主要是先get 保证自己仍然持有这把锁,然后delete释放这把锁,保证原子性即可

//加锁解锁 start

    //lock script
    private static final String lockScript = " if redis.call('setnx',KEYS[1],ARGV[1]) == 1 " +
            " then redis.call('expire',KEYS[1],ARGV[2]) " +
            " return 1 " +
            " else return 0 end ";

    /**
     * 加锁
     * @param key
     * @param value
     * @param second 锁过期时间
     * @return
     */
    public boolean lock(String key,String value,Long second){
        DefaultRedisScript<Boolean> script = new DefaultRedisScript<>();
        script.setScriptText(lockScript);
        script.setResultType(Boolean.class);
        return stringRedisTemplate.execute(script,Collections.singletonList(key),value,second+"");
    }


    //unlock script
    private static final String unlockScript = " if redis.call('get',KEYS[1]) == ARGV[1] " +
                            " then return redis.call('del',KEYS[1]) " +
                            " else return 0 end ";


    /**
     * 解锁
     * @param key
     * @param value
     * @return
     */
    public boolean unlock(String key,String value){
        DefaultRedisScript<Boolean> script = new DefaultRedisScript<>();
        script.setScriptText(unlockScript);
        script.setResultType(Boolean.class);
        return stringRedisTemplate.execute(script,Collections.singletonList(key),value);
    }

接口限流

接口限流有很多方案,
1,从配置上来说,可以在网关层做,比如ng的配置,也可以在web服务器上做,比如tomcat的相关配置
2,从算法来说,比如令牌,漏桶等等
这里咱们的需求是针对分布式环境下,单个用户对某个接口的访问进行限流
需求:对某接口每分钟请求数不超过60次(单个用户60Qps)
这里我们简单一点,使用redis的zset
伪代码如下:
以用户id为key,每次请求先判断指定时间范围内改用户的请求记录 (zcount min max),如果大于等于60,则直接return掉;如果小于60,则 zadd key value 当前时间戳
这里只要将这两步操纵合并到同一个脚本中即可。
代码如下:

private static final String scripts = "if redis.call('zcount',KEYS[1],ARGV[1],ARGV[2] ) < tonumber(ARGV[3])  " +
            "then return redis.call('zadd',KEYS[1],ARGV[4],ARGV[5])  " +
            "else return 0  " +
            "end";

    /**
     * 
     * @param userKey
     * @param min
     * @param max
     * @param maxV
     * @param value
     * @param score
     * @return
     */
    public boolean getToken(String userKey,String min,String max,String maxV,String value,String score){
        DefaultRedisScript<Boolean> script = new DefaultRedisScript<>();
        script.setScriptText(scripts);
        script.setResultType(Boolean.class);
        return  stringRedisTemplate.execute(script,Collections.singletonList(userKey),min,max,maxV,value,score);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容