redis分布式锁一般采用setnx(set if not exists)指令实现,先针对key进行加锁,使用完后删除锁。
但是如果业务逻辑处理时出现异常或者redis进程出现异常,导致del指令没有执行,这样就会造成死锁。
针对这种问题,可以设置锁的过期时间,如果del指令未执行,则到期自动释放锁,但是setnx指令和expire指令不是原则的,有可能setnx指令已经执行,但是expire指令尚未执行时,redis进程故障,同样会导致死锁。
所以在2.8版本之后,redis作者扩展了set指令参数,是setnx指令和expire指令可以原子执行,即便del指令未执行,到期后依然可以释放锁,避免了死锁。
但是这样依旧存在不足:业务逻辑的执行可能需要比较长的时间,如果过期时间设置为5秒,业务逻辑执行需要10秒时间,这样当5秒到期锁被释放了,第二个线程依旧可以拿到这个锁。所以redis分布式锁不适用于业务逻辑比较复杂,执行时间较长的场景,另外,我们可以在设置set指令value时设置为一个随机数,释放锁的时候先判断随机数是否一致,确保set和del是同一个线程,避免一个线程的锁被另一个线程释放。