暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

redis-------分布式锁的实现方式

Lord Lean Notes 2020-03-07
518

redis是我们在工作中最常接触到的中间件,这个中间件的作用最经常用来做缓存、缓存数据库等功能。redis也是可以实现分布式锁的,我们可以通过redis+lua脚本的方式来实现加锁和释放锁的操作。下面来看实现方式:

    /**
    * redisTemplate 加锁
    * @param key
    * @return
    */
    public boolean setNxLock(String lockKey, String value, int expireTime){
    boolean ret = false;
    try{
    String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";


    RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);


    // Object result = redisTemplate.execute(redisScript, (List<String>) new StringRedisSerializer(), Collections.singletonList(lockKey),value,expireTime + "");


    Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey),value,expireTime + "");
    System.out.println(result + "-----------");
    if(SUCCESS.equals(result)) {
    return true;
    }
    }catch(Exception e){
    e.printStackTrace();
    }
    return ret;
    }
    /**
    * 释放锁
    * @param lockKey
    * @param value
    * @return
    */
    public boolean releaseLock(String lockKey, String value){


    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";


    RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);


    Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey),value);
    if(SUCCESS.equals(result)) {
    return true;
    }
    return false;
    }
    上面的实现方式是通过给key设置过期时间来保证key绝对会过期,我们工作中最常使用的方式也是这种。但是当在如果业务代码的运行时间超过了加锁的时间,又或者redis的主服务器发生宕机,并且主从同步的加锁消息没有发送到从服务器,而导致另一个业务在从服务器上加锁时发现加锁操作并未成功。 
    下面我们就针对这两种情景说出小编自己所思考到的解决方案:
    第一种:加锁时间已经失效但是业务代码未运行完毕的情况

    我们可以采用redisson客户端工具来实现分布锁,

    redission客户端工具通过可重入锁的方式来实现锁,并且在redisson实例存活时,会根据Config.lockWatchdogTimeout来实时检查是否运行完毕,当未运行完毕时,就会延长时间。而如果redisson实例宕机之后,过了加锁时间就会自动解开。而当其他客户端对同一个资源进行加锁时,如果仍未解锁,则会返回剩余时间,然后通过while循环不断尝试加锁。

    redisson客户端工具的实现原理:

    第二种:加完锁之后主服务器宕掉,导致从服务器加锁发生脏数据

    这种情况小编想到的是可以通过哨兵模式来搭建主从,同时开始aof持久化的方式,配置好写入aof日志内容的时机。redis发生宕机的可能性还是比较小的,所以一般采用第一种方式就可以,第二种可以结合具体情况来处理。

    文章转载自Lord Lean Notes,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论