加锁姿势
1、setNotExist命令了解;
2、为了防止死锁,需要设置超时时间;
3、设置锁:key-value时需要同时指定超时时间,避免服务突然宕机产生死锁问题;
4、加锁成功设置延迟检查任务,比如超时时间的一半执行锁状态检查,若资源依旧处于处理占有中,则需要对锁做‘续命’操作,防止超时自动释放锁导致进程间并发安全问题,并且需要设置续命次数上限,必要时打印关键日志警告;
5、设置锁时需要将value设置为一个能够区分各个客户端的id(比如uuid),用于释放锁时判断,避免误删;(意思就是a节点设置的锁,只能是a节点来删除(除非达到续命上限,超时自动释放));
private static final String LOCK_SUCCESS = "OK";
// nxxx NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the key if it already exist.
private static final String SET_IF_NOT_EXIST = "NX";
// expire time units: EX = seconds; PX = milliseconds
private static final String SET_WITH_EXPIRE_TIME = "PX";
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
// nxxx NX|XX, NX -- Only set the key if it does not already exist. XX
// expire time units: EX = seconds; PX = milliseconds
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
解锁姿势
1、解锁需要保证命令的原子性,使用脚本进行封装;谁加的锁谁来解
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
// 根据result做判断