场景描述
最近使用 Redis 遇到了一个类似分布式锁的场景,跟 Redis 实现分布式锁类比一下,就是释放锁失败,也就是缓存删不掉。又踩了一个 Redis 的坑……
这是什么个情况、又是怎样排查的呢?
本文主要对此做个复盘。
问题排查
既然是释放锁有问题,那就先看看释放锁的代码吧。
释放锁
释放锁使用了 Lua 脚本,代码逻辑和 Lua 脚本如下:
- 释放锁示例代码
public Object release(String key, String value) {
Object existedValue = stringRedisTemplate.opsForValue().get(key);
log.info("key:{}, value:{}, redis旧值:{}", key, value, existedValue);
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(COMPARE_AND_DELETE, Long.class);
return stringRedisTemplate.execute(redisScript, Collections.singletonList(key), value);
}
- 释放锁使用的 Lua 脚本
if redis.call('get',KEYS[1]) == ARGV[1]
then
return redis.call('del',KEYS[1])
else
return 0
end;
删除脚本中,会先获取 Redis key 的旧值,并与入参 value 比较,二者相等时才会删除。
如果释放成功,也就是 Redis 缓存删除成功,返回值为 1,否则失败返回为 0。
乍一看代码似乎没啥问题,测一下试试?
不过既然要释放锁,在此之前肯定要加锁,先看看加锁的逻辑吧。
加锁
说到加锁这里的逻辑,代码里有两种实现方式:
- 示例代码一
public Object lock01(String key, String value) {
log.info("lock01, key={}, value={}", key, value);
return redisTemplate.opsForValue().setIfAbsent(key, value, LOCKED_TIME, TimeUnit.SECONDS);
}
- 示例代码二