Featured image of post 一文搞懂Redis分布式锁下篇(集群版RedLock)

一文搞懂Redis分布式锁下篇(集群版RedLock)

一、Redlock算法的Java落地实现Redisson

目前大多数基于Redisde分布式锁的实现,都有上面章节所说的问题。如果是使用单机的Redis上面的例子就够用了,但是一般在使用Redis时,为了保证Redis的可用性一般都是使用Redis集群。

在上篇中单机版Redis环境下的Redis分布式锁(上篇)提到的单机版Redis分布式锁实现的代码在集群环境下的问题Redis官网文档关于分布式锁章节中也说到了,因此提出了RedLock算法。

二、RedLock的设计理念

2.1 Redis集群的AP导致的问题

分布式问题,就不得不说一下CAP理论:C一致性、A可用性、P分区容错性。一般分布式系统设计要么是AP,要么就是CP,而Redis集群则是CP,在往Redis的Master节点写入数据后,会通过异步复制同步到Slave节点上,这过程中Redis集群依然是向外提供服务的。

这时候如果Master节点没来得及把刚刚写进Redis的Key同步给Slave节点就挂了,此时Slave节点升级为Master节点,Key没成功同步,这就会导致锁丢失了。

2.2 设计理念

该方案也是基于set命令枷锁和lua脚本实现的。假设有N个Redis节点,例如N=5,这些节点之间是完全独立,我们不适用复制或者任何协调系统,客户端要获取锁的步骤如下:

  1. 获取当前时间,以毫秒为单位。

  2. 依次尝试从5个实例中,使用相同的key和随机值获取锁。当向Redis请求获取锁时,客户端应该设置一个超时时间,这个超时时间应该小于锁的失效时间。例如锁的自动失效时间为10秒时,则超时时间因该在5-50毫秒之间。这样可以防止客户端在试图与一个当即的Redis节点对话长时间处于阻塞状态。如果一个实例不可用,客户端应该尽快尝试去与另外一个Redis实例请求获取锁。

  3. 客户端通过当前时间减去步骤 1 记录的时间来计算获取锁使用的时间。当且仅当从大多数(N/2+1,这里是 3 个节点)的 Redis 节点都取到锁,并且获取锁使用的时间小于锁失效时间时,锁才算获取成功。

  4. 如果取到了锁,其真正有效时间等于初始有效时间减去获取锁所使用的时间(步骤 3 计算的结果)。

  5. 如果由于某些原因未能获得锁(无法在至少 N/2 + 1 个 Redis 实例获取锁、或获取锁的时间超过了有效时间),客户端应该在所有的 Redis 实例上进行解锁(即便某些Redis实例根本就没有加锁成功,防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁)。

该方案为了解决数据不一致的问题,直接舍弃了异步复制只使用 Master 节点,同时由于舍弃了 Slave,为了保证可用性,引入了 N 个节点,官方建议是 5。

客户端只有在满足下面的这两个条件时,才能认为是加锁成功: 条件1:客户端从超过半数(大于等于N/2+1)的Redis实例上成功获取到了锁; 条件2:客户端获取锁的总耗时没有超过锁的有效时间。

2.3 解决方案

因为Redis集群只支持AP,为了解决一致性的风险,采用N个节点,N为奇数,N个Master节点之间各自互相独立,不是互为主从或者集群。N=2X+1,其中N为最终部署的Redis节点数,X时容错机器数。

为什么容错呢?

失败了多少个机器实例后我还是可以容忍的,所谓的容忍就是数据一致性还是可以Ok的,CP数据一致性还是可以满足:

  1. 加入在集群环境中,redis失败1台,可接受。2X+1 = 2 * 1+1 =3,部署3台,死了1个剩下2个可以正常工作,那就部署3台。

  2. 加入在集群环境中,redis失败2台,可接受。2X+1 = 2 * 2+1 =5,部署5台,死了2个剩下3个可以正常工作,那就部署5台。

为什么N是奇数呢?

最少的机器,最多的产出效果:

  1. 加入在集群环境中,redis失败1台,可接受。2N+2= 2 * 1+2 =4,部署4台
  2. 加入在集群环境中,redis失败2台,可接受。2N+2 = 2 * 2+2 =6,部署6台

三、总结与预告

分布式锁是最常用的分布式技术,其中的实现有很多,这里这里通过两篇文章详说了其中的优缺点和存在的问题。

单机版的Redis已经符合中小型的系统使用,大型的分布式系统,可不能单单靠一个Redis实例支撑,必定是上分布式集群或主从架构,Redis分布式集群比较常用就是三主三从,主从结构一主多从则看具体的系统了,一引入Redis集群,便会带来一致性的问题。此时可以使用官方推荐的RedLock的实现:https://redis.io/topics/distlock。

在本片所述,加入Redis集群环境,除了要部署N个各自独立的Master Redis实例,再加上各自Master节点所在集群Slave节点,要部署的Redis实例也所需不少,关于是否使用Red Lock还是看各自的选择或者自己有更好的方法。

这里关于Redis分布式锁就讲到这里,后面会再写一下集群版Redis分布式锁的实操!