使用redis實現(xiàn)的分布式鎖,真正想要分布式鎖還是用zk做好毡证,redis的實現(xiàn)還是有風(fēng)險转砖,簡單用用還可以。
- redis集群中根據(jù)key進行哈希分配到不同的hash槽诞外,如果某個槽的機器down了澜沟,相當(dāng)于這些key都解鎖了。
- 如果程序執(zhí)行時間過長峡谊,鎖就被自動釋放了茫虽。而且也不可能不加過期時間,否則剛加完鎖既们,機器down了濒析,這個鎖就永遠(yuǎn)得不到釋放
- 使用zk的話,通過臨時節(jié)點加watcher可以完美避開redis分布式鎖的這些問題啥纸,就是加鎖解鎖寫起來比較復(fù)雜
- 使用redis實現(xiàn)的分布式鎖主要有兩點要注意:1.對redis的操作保持原子悼枢。2.保持誰加的鎖誰釋放。原理比較簡單脾拆,不用細(xì)說了
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)) { // 設(shè)置成功
return uuid;
}
// 設(shè)置失敗
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官網(wǎng)的寫法~品質(zhì)有保證