使用redis实现的分布式锁,真正想要分布式锁还是用zk做好,redis的实现还是有风险,简单用用还可以。
- redis集群中根据key进行哈希分配到不同的hash槽,如果某个槽的机器down了,相当于这些key都解锁了。
- 如果程序执行时间过长,锁就被自动释放了。而且也不可能不加过期时间,否则刚加完锁,机器down了,这个锁就永远得不到释放
- 使用zk的话,通过临时节点加watcher可以完美避开redis分布式锁的这些问题,就是加锁解锁写起来比较复杂
- 使用redis实现的分布式锁主要有两点要注意:1.对redis的操作保持原子。2.保持谁加的锁谁释放。原理比较简单,不用细说了
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;
}
}
- 注意,这是redis官网的写法~品质有保证

网友评论