前面写了一篇关于用Redis来解决秒杀业务场景下超卖的文章,罗列了秒杀场景下,为什么会超卖?如何解决超卖?使用Redis分布式锁有哪些问题?提到了几种实现技术方案。原文链接。感兴趣的可以阅读。
今天继续给大家分享一篇关于Redis分布式锁的文章,其中的主角就是Redis作者提到的redlock。
在上一篇文章的结尾处,我当时提出了这样一个问题。如果是集群、主从复制和哨兵模式的部署模式情况下,Redis的分布式锁如何保证实现高可用。大家看到此处的时,可以先思考一下,如何保证?
Redlock是Redis作者针对集群、主从复制等业务场景下,用Redis实现分布式锁高可用的一种实现算法,主要是保证Redis服务不可用场景下的锁失效问题。
这种算法具体是怎么实现的呢?就是部署多台与master节点同等级别的其他节点,这几个Redis不参与其他的业务。每一个线程在向master节点请求锁的同时,也向这几个同等级别的节点发送加锁请求,只有当超过一半的节点数加锁成功,此时的分布式锁才算真正的成功。大致的逻辑图如下:
假设我们的Redis部署架构是一主多从的模式,每一个thread都会往master节点写入数据,读数据都是从slave节点读数据。大致的架构模式如下:
Redis的主从复制是异步操作的,就是说客户端在向master发送写数据之后,master不会马上把写入的数据发送给slave节点,而是先响应客户端写入数据成功之后在把新写入的数据同步给slave节点。
slave升级为master节点
,升级为master节点的slave节点此时是没有锁数据的。其他的thread肯定会进行加锁操作。试想一下,此时整个系统只会存在一把锁吗?这里需要注意一下,slave切换master之后,之前的master在服务恢复之后变为slave,会情况自身的所有数据。
通过上面的分析,我们就不难得出,Redis分布式锁在高可用架构的模式下并不一定完全可靠。因此,Redlock就诞生了。
成功获取锁数量 >= (节点数) / 2 + 1
。奇数个是为了提高加锁成功的概念。试想一下如果是4个几点,一半加锁成功,一半加锁失败,各自占50%的几率。只有成功超过或者失败的概率超过50%,此时我就才好判断是成功与否。在Redloc定义中提到了实现的思路,下面使用伪代码
演示,从代码层面该如何去实现。其实Redlock的加锁逻辑和上一篇文章提到的单机加锁逻辑都是一样的,无非就是多了记录加锁时长、判断加锁成功与否的情况处理。
function redLock()
{
// 记录加锁开始时间(这里简单一点,就用秒为单位了。实际情况用毫秒记录。)
$lockBeginTime = time();
// 锁时长
$expireTime = 3;
$redisClient = new Redis();
// 1. 向master节点发送加锁请求
$result1 = $redisClient->set('key', 'clientId', ['nx', 'px' => $expireTime * 1000]);
// 2. 向node1发送加锁请求
$result2 = $redisClient->set('key', 'clientId', ['nx', 'px' => $expireTime * 1000]);
// 3. 向node2发送加锁请求
$result2 = $redisClient->set('key', 'clientId', ['nx', 'px' => $expireTime * 1000]);
// 4. 向node3发送加锁请求
$result3 = $redisClient->set('key', 'clientId', ['nx', 'px' => $expireTime * 1000]);
// 记录加锁结束时间(实际情况下,同样使用毫秒。)
$lockEndTime = time();
// 判断加锁是否成功
if ($result1 && $result2 && $result3 && ($lockEndTime-$lockBeginTime) < $expireTime) {
// 加锁成功,执行对应的业务逻辑代码。
// 释放锁
} else {
// 加锁失败,执行释放锁操作。
}
}
一定要记住,在进行释放锁的时候,需要向每一个加锁的节点发送释放锁请求。
上面的示例代码,都是使用的同步操作去加锁和解锁。在这个过程中无疑是增加了时间上的成本消耗。某一个加锁比较慢,也很容易导致加锁失败。因此推荐在加锁和解锁的过程都采用多线程去执行加锁。
罗列一下个人对分布式锁中需要特别注意的事项做几个总结。这几点属于个人总结,大家阅读时,需要多多思考是否完全正确。
同一时刻
,只有一个线程能够获取到资源的执行权,其他的线程是不能对该资源进行操作。这也可以理解为锁互斥。Anything is possible, but nothing is easy.
。通过上面的分析,咱们基本明白了Redlock的一个实现原理。可能你也会觉得这样实现分布式锁已经没问题了,这样你就大错特错了。当Redis作者提出该概念之后,就受到很多质疑,因为这样实现分布式锁也会存在很多的问题。下面罗列一些个人现目前认知水平已经能够知道的和Redis官网的说明。后面有其他的认知,也会更新。