redis集群状态下的问题: 1. 客户端A从master获取到锁 2. 在master将锁同步到slave之前,master宕掉了。 3. slave节点被晋级为master节点 4. 客户端B取得了同一个资源被客户端A已经获取到的另外一个锁。 安全失效! 解决集群下锁失效,参照redis官方网站针对redlock文档:https://redis.io/topics/distlock 在算法的分布式版本中,我们假设有N个Redis服务器。这些节点是完全独立的,因此我们不使用复制或 任何其他隐式协调系统。
在分布式锁算法 中,将使用相同的方法在单个实例中获取和释放锁。将N设置为5是一个合理的值,因此需要在不同的 计算机或虚拟机上运行5个Redis主服务器,确保它们以独立的方式发生故障。 为了获取锁,客户端执行以下操作:
1. 客户端以毫秒为单位获取当前时间的时间戳,作为起始时间。
2. 客户端尝试在所有N个实例中顺序使用相同的键名、相同的随机值来获取锁定。每个实例尝试获取 锁都需要时间,客户端应该设置一个远小于总锁定时间的超时时间。例如,如果自动释放时间为 10秒,则尝试获取锁的超时时间可能在5到50毫秒之间。这样可以防止客户端长时间与处于故障状 态的Redis节点进行通信:如果某个实例不可用,尽快尝试与下一个实例进行通信。
3. 客户端获取当前时间 减去在步骤1中获得的起始时间,来计算获取锁所花费的时间。当且仅当客户 端能够在大多数实例(至少3个)中获取锁时,并且获取锁所花费的总时间小于锁有效时间,则认 为已获取锁。
4. 如果获取了锁,则将锁有效时间减去 获取锁所花费的时间,如步骤3中所计算。
5. 如果客户端由于某种原因(无法锁定N / 2 + 1个实例或有效时间为负)而未能获得该锁,它将尝试 解锁所有实例(即使没有锁定成功的实例)。 每台计算机都有一个本地时钟,我们通常可以依靠不同的计算机来产生很小的时钟漂移。只有在拥有锁 的客户端将在锁有效时间内(如步骤3中获得的)减去一段时间(仅几毫秒)的情况下终止工作,才能 保证这一点。以补偿进程之间的时钟漂移 当客户端无法获取锁时,它应该在随机延迟后重试,以避免同时获取同一资源的多个客户端之间不同步 (这可能会导致脑裂的情况:没人胜)。同样,客户端在大多数Redis实例中尝试获取锁的速度越快, 出现裂脑情况(以及需要重试)的窗口就越小,因此理想情况下,客户端应尝试将SET命令发送到N个 实例同时使用多路复用。 值得强调的是,对于未能获得大多数锁的客户端,尽快释放(部分)获得的锁有多么重要,这样就不必 等待锁定期满才能再次获得锁(但是,如果发生了网络分区,并且客户端不再能够与Redis实例进行通 信,则在等待密钥到期时需要付出可用性损失)。