场景描述最近Redis遇到了类似分布式锁的场景。对比Redis实现分布式锁,释放锁失败,即无法删除缓存。又踩了一个Redis的坑……这是什么情况,怎么查看?本文主要对此进行评述。排查问题既然释放锁有问题,那我们先来看一下释放锁的代码。释放锁释放锁使用Lua脚本,代码逻辑和Lua脚本如下:释放锁示例代码publicObjectrelease(Stringkey,Stringvalue){ObjectexistedValue=stringRedisTemplate.opsForValue().get(key);log.info("key:{},value:{},redis旧值:{}",key,value,existedValue);DefaultRedisScriptredisScript=newDefaultRedisScript<>(COMPARE_AND_DELETE,Long.class);returnstringRedisTemplate.execute(redisScript,Collections.singletonList(key),value);}用于释放锁的lua脚本ifredis.call('get',KEYS[1])==ARGV[1]thenreturnredis.call('del',KEYS[1])elsereturn0end;在删除脚本中,会先获取Rediskey的旧值,与输入参数值进行比较,相等时才删除。如果释放成功,即成功删除Redis缓存,则返回值为1,否则返回值为0。乍一看,代码似乎没有问题。试试看?但是既然需要释放锁,那么就必须在这之前加锁。我们来看看加锁的逻辑。Locking说到加锁的逻辑,代码中有两种实现方式:示例代码一publicObjectlock01(Stringkey,Stringvalue){log.info("lock01,key={},value={}",key,value);returnredisTemplate.opsForValue().setIfAbsent(key,value,LOCKED_TIME,TimeUnit.SECONDS);}示例代码2publicObjectlock02(Stringkey,Stringvalue){log.info("lock02,key={},value={}",key,value);returnstringRedisTemplate.opsForValue().setIfAbsent(key,value,LOCKED_TIME,TimeUnit.SECONDS);}其实它们的区别在于前者使用的是RedisTemplate,后者使用的是StringRedisTemplate。问:等等……为什么有两个模板??A:我说了,我挖坑了,我加了RedisTemplate……现在想想,我想不通当初为什么要这么做。也许是抽搐了。.先测试这两种方法?分别使用两种方式加锁进行测试,其中:lock01为k1和v1,lock02为k2和v2。分别看k1和k2的值(使用工具:RDM、RedisDesktopManager):可以看到v1有双引号,v2没有。猜测应该是序列化问题。看看Redis的配置?RedisTemplate配置已锁定。可以看到k1使用的是RedisTemplate,k2是StringRedisTemplate。两种配置有什么区别?RedisTemplate的配置是自定义的,如下:@Configuration@AutoConfigureAfter(RedisAutoConfiguration.class)publicclassRedisConfig{@BeanpublicRedisTemplateredisTemplate(RedisConnectionFactoryredisConnectionFactory){RedisTemplateredisTemplate=newRedisTemplate<>();redisTemplate.setConnectionFactory(redisConnection/工厂使用);Jackson2JsonRedisSerialize替换默认序列化Jackson2JsonRedisSerializer