分布锁要求
安全:同一时间只能一个客户端持有锁
无死锁:锁设置过期时间
容错性:只要大部分redis节点存活,分布锁就能使用
Lua脚本实现(单例)
加锁
set key value px milliseconds nx
nx 如果不存在,则设置
xx 存在,则设置
px 设置锁过期时间为毫秒
ex 设置锁过期时间为秒
解锁
String luaScript = “local in = ARGV[1] local curr=redis.call(‘get’, KEYS[1]) if in==curr then redis.call(‘del’, KEYS[1]) end return ‘OK’””;
RedisScript
redisTemplate.execute(redisScript, Collections.singletonList(key), Collections.singleton(val));
Redisson实现
RedissonClient redissonClient = Redisson.create(config);
RLock rLock = redissonClient.getLock(lockKey);
try {
boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);
if (res) {
//成功获得锁,在这里处理业务
}
} catch (Exception e) {
}finally{
//释放锁
rLock.unlock();
}
waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
leaseTime 锁的持有时间,超过这个时间锁会自动失效
(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
存在问题
客户端a获取到锁,锁存储在节点A上
节点A故障,并且锁信息未存储到从节点
从节点提升为主节点
客户端b获取到a获取到的锁资源