程序员技术交流java后端集群化专题数据库

redis实现的分布式锁

2018-07-11  本文已影响28人  江江的大猪

使用redis实现的分布式锁,真正想要分布式锁还是用zk做好,redis的实现还是有风险,简单用用还可以。

  1. redis集群中根据key进行哈希分配到不同的hash槽,如果某个槽的机器down了,相当于这些key都解锁了。
  2. 如果程序执行时间过长,锁就被自动释放了。而且也不可能不加过期时间,否则刚加完锁,机器down了,这个锁就永远得不到释放
  3. 使用zk的话,通过临时节点加watcher可以完美避开redis分布式锁的这些问题,就是加锁解锁写起来比较复杂
    private static final int LOCK_SECOND = 60;
    private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    private static final String LOCK_SUCC = "OK";
    private static final Long UNLOCK_SUCC = 1L;

    public String lock(String key) {
        if (StringUtils.isBlank(key)) {
            return StringUtils.EMPTY;
        }
        key = StringAssist.joinUnderline(RedisKey.DISTRIBUTED_LOCK_PRE, key);
        String uuid = UUID.randomUUID().toString();
        try (Jedis jedis = pool.getResource()) {
            String setRet = jedis.set(key, uuid, "NX", "EX", LOCK_SECOND);
            if (StringUtils.equals(setRet, LOCK_SUCC)) { // 设置成功
                return uuid;
            }
            // 设置失败
            return StringUtils.EMPTY;
        } catch (Exception e) {
            log.error("lock error, key:{}", key, e);
            return StringUtils.EMPTY;
        }
    }

    public boolean unlock(String key, String uuid) {
        if (StringUtils.isAnyBlank(key, uuid)) {
            return false;
        }
        key = StringAssist.joinUnderline(RedisKey.DISTRIBUTED_LOCK_PRE, key);
        try (Jedis jedis = pool.getResource()) {
            Object result = jedis.eval(UNLOCK_SCRIPT, Collections.singletonList(key), Collections.singletonList(uuid));
            if (UNLOCK_SUCC.equals(result)) {
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("unlock error, key:{}", key, e);
            return false;
        }
    }
e5c4fde85281bebb0295e91512ec34cd.jpg
上一篇下一篇

猜你喜欢

热点阅读