这里说的集群模式为 sentinel 和 cluster 模式 (PS : 本人对于 sentinel 和 cluster 两种集群模式还处于学习阶段)
相关redLock 官方介绍(PS : 里面包含了算法的思想以及相关代码演示)
https://redis.io/topics/distlock
对于分布式服务和分布式redis情况下, 对于分布式锁依然要求 安全性和可用性
- 关于安全性: 根据官方介绍,根据锁互斥的特点,要求最多只能有一个服务端client 加锁成功
- 关于可用性:
- 避免死锁,即使说成功获取锁的客户端崩溃也不会影响到其他客户端后续加锁操作;
- 容错性,即使在发生redis客户端宕机或重启情况下,仍然能保证服务正常加锁和解锁操作;
单机版 分布式锁的实际就是利用的 "set nx ex 时间"命令来实现加锁的操作,而对于分布式服务的控制,则是会在value中存储客户端相关信息来标记当前锁所属的服务客户端
锁获取
根据redlock 算法的思想 , 其并不是利用主备节点,会尝试操作所有的主节点,对于其加锁的流程为按照顺序依次对所有的主节点进行加锁操作; 对于加锁成功的标记 实际 就是分布式系统理论中的多数选举规则,只要满足半数以上redis客户端加锁成功,就认为当前服务获取锁成功;每个节点加锁和释放锁的操作和单机版一样
因此为了满足多数选举的规则,避免"脑裂"情况的发生,因此一般集群主节点要求为单数
对于当前分布式情况下redis加锁,特别需要控制每个节点尝试加锁时间,原因在于 对于服务端发起加锁请求时实际存在一个总时间限制,因此要求在每个节点上尝试加锁总时间不能影响到整体锁存活时间
对于分布式情况下也会存在加锁失败的情况,对于加锁失败时就需要执行释放锁操作,原因是可能在多个节点已经加锁成功,只是没有满足分布式最终加锁成功的条件,因此需要去释放当前服务所有成功获取到单个节点上的锁
锁释放
对于释放锁的操作和分布式加锁的流程也是一致的也是需要顺序遍历所有的主节点,对于遍历过程中可能会出现以下情形
- 当前节点上不存在当前key, 直接跳过
- 当前节点上存在当前key, 则需要获取当前key中存储的value,根据value中的相关自定义标识来判断当前锁是否属于当前请求的客户端,
- 如果属于当前请求的客户端,则执行删除操作
- 反之如果不属于,则继续递归下一个节点,依次重复之前的 1,2操作,直到遍历完全部的节点
//TODO : 具体代码演示