聊一聊Redis官方置顶推荐的Java客户端Redisson( 三 )


解锁时通过Lua脚本先检查锁是否存在,如果已经不存在则直接发布解锁消息并返回 。如果仍然存在则检查标签是否存在,如果不存在则表示这个锁并不为本线程所拥有,这种情况请求线程将收到报错 。如果存在则表示该锁正是被该线程所拥有 。在这种情况下,递减标签字段后判断,如果返回的加锁数量仍然大于0,说明当前的锁仍然有效,仅仅只是重入次数减少了 。相反这表示锁已经完全解开,则立即删除该锁并发布解锁信息 。
Redisson的可重入锁解决了setnx锁的许多先天性不足,但是由于它仍然是以单一一个key的方式储存在固定的一个Redis节点里,并且有自动失效期 。这样的设计虽然可以很大程度上避免客户端程序宕机或业务节点挂掉造成的影响,但是随之带来的弊端是遇到服务端Redis进程宕机或节点挂掉的情况,还是有可能会造成锁的信息丢失,这样的缺陷显然无法满足某些特定场景提出的高可用性要求 。
介于这种情况,Redis作者Salvatore提出了一个基于多个节点的高可用分布式锁的算法,起名叫红锁(RedLock: https://redis.io/topics/distlock) 。在这种算法下,客户端需要同时在多个节点里同时尝试获取一个独立的锁,只有当一次性成功获取了大多数锁的情况下才能被视为赢得了高可用分布式锁,否则需要解除已经部分获取到的锁,等待一个随机时间后再次重试 。
在算法设计上,Salvatore依然采用的是setnx作为举例讲解分布式锁的互斥特性 。在算法实现上,Redisson的RedissonRedLock采用的是前面提到的更加灵活方便的可重入锁 。Redisson的扩展算法是Redis官网唯一认可的Java实现 。
虽然Redlock的算法提供了高可用的特性,但建立在大多数可见原则的前提下,这样的算法适用性仍然有一定局限 。Redisson为此提供了基于增强型的算法的高可用分布式联锁RedissonMultiLock 。这种算法要求客户端必须成功获取全部节点的锁才被视为加锁成功,从而更进一步提高了算法的可靠性 。




推荐阅读