redis锁失效场景,什么情况下会失效,有没有有效的解决方法
redis键过期锁就失效了,根据加锁场景,使用合适的过期时间。
如果是单节点Redis,Redis锁失效的场景:
如果是集群部署的Redis,此时的Redis锁是分布式锁,其失效的场景:
有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用。
在以下两种情况下,使用Redis锁可能会失效:
解决方案:
@Component
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
private static final Long RELEASE_SUCCESS = 1L;
//加锁
public boolean lock(String key, String requestId, long expireTime) {
String script = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<Long>(script, Long.class);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId, expireTime);
return RELEASE_SUCCESS.equals(result);
}
//释放锁
public boolean unlock(String key, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<Long>(script, Long.class);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);
return RELEASE_SUCCESS.equals(result);
}
}
以上示例代码中,用到了Lua脚本的原子性操作,可以保证加锁和释放锁的操作是原子性的,并且使用了Redis的setnx命令来尝试加锁,成功则将锁的过期时间设置,失败则返回0,表示该锁已被其他客户端占用。在释放锁时,使用Lua脚本的get和del命令判断锁的持有者是否为当前客户端,如果是则释放锁,否则返回0,表示该锁已被其他客户端占用。由于使用Lua脚本,可以保证加锁和释放锁的操作是原子性的,避免了由于网络问题等原因导致锁没有释放的情况。