redis之作为分布式锁使用

写在前面

在这里插入图片描述
本文一起看下redis作为分布式锁使用的相关内容。

1:怎么算是锁或没锁

锁和没锁本身其实就是用一个变量的值来表示,比如变量lock,当值为1时代表处于上锁状态,当值为0时表示没有锁,那么多线程想要获取锁的话就是判断当前lock值是否为0,如果是的话则将其设置为1,则代表该线程获取到了锁,释放锁的过程就是将lock的设置为0。当然,基本原理就是这样,实际中可能略有不同。伪代码可能如下:

在这里插入图片描述

接下来我们分别从基于单实例redis和多实例redis两种情况来看下如何加锁。

1.1:单实例redis

我们前面分析了,加锁其实就是对一个变量赋予特定值,成功则是加锁成功,否则则是加锁失败,还有就是,这个过程必须是原子的,我们也知道,redis中的原子操作有两种,第一种是单命令,第二种是lua脚本,我们先看第一种,redis提供了命令setnx ,该命令的行为是如果是key不存在,则设置,否则什么也不做,如下:

127.0.0.1:6379> setnx aaaaa bbbb
(integer) 1
127.0.0.1:6379> setnx aaaaa bbbb
(integer) 0

可以看到再次调用就返回0了。因此可以使用其来实现加锁的操作,其实这样还是不够的,因为缺少释放锁的操作,释放也很简单,只需要执行del 但是此时可能存在如下2个问题:

1:如果最终del没有执行成功,则锁将会一直不能释放
2:执行del的线程不一定是加锁的线程,如线程A加锁了,但是线程B执行了del,但此时线程A还没有执行完毕,线程C又拿到了锁,就会出现问题了

对于1,可以通过expire 命令来设置过期时间,对于2,我们可以给每个客户端分配特有的值,进行设置,即setnx key val中的val每个客户端都是不一样的,在进行删除的时候,判断当前是否为自己加的锁,是才del,否则不操作,为了保证原子性,我们需要使用lua脚本来实现这个锁的过程:

// local key = KEYS[1]
// local val = redis.call("GET", key);
// 其中ARGV[1]代表的是客户端设置的值,只有当前值是自己设置的时候才执行删除key操作
if redis.call("GET", KEYS[1]) == ARGV[1]
then
        redis.call('del', KEYS[1])
        return 1
else
        return 0
end 

其实,以上对于问题1,还需要单独再执行一个命令expire,这显然会影响到程序的性能,对于这点,我们可以使用set命令来完成,不存在才设置值以及同时设置过期时间,该命令格式如下:

set key value [EX seconds] [PX milliseconds] [NX|XX] 

其中NX用来设置当key不存在时才设置,PX用来设置过期的时长,此时加锁代码可能如下:

127.0.0.1:6379> set lock:key client_val NX PX 10000
OK

即10秒后过期并删除。解锁lua脚本可能如下:

local key = KEYS[1]
local val = redis.call("GET", key);

// 其中ARGV[1]代表的是客户端设置的值,只有当前值是自己设置的时候才执行删除key操作
if val == ARGV[1]
then
        redis.call('del', KEYS[1])
        return 1
else
        return 0
end 

其实和使用setnx命令的解锁方式是一样的。单实例锁的问题是,一旦实例宕机,就没有办法加锁和解锁了,应用程序也就无法正常运行了。

1.2:多实例redis锁

因为是多个实例同时操作,所以加锁过程一定要遵循一定的规范和过程,redlock分布式锁算法就描述了这样的一个规范和过程,该算法如下:

1:记录当前系统的时间
2:使用set k v NX PX millisec 完成加锁
3:所有实例加锁完成后,按照如下条件判断是否加锁成功
    3.1:是否超过半数的实例加锁成功
    3.2:当前时间减去第一步记录的加锁开始时间是否超过了锁的超时时间,没超过则成功

释放锁的过程和单实例类似,只不过需要每个实例上都执行释放锁的lua脚本。

这种加锁方式其实就是redlock。

写在后面

参考文章列表:

Redlock:Redis分布式锁最牛逼的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值