Redis分布式锁实现简述

2022/1/20 19:12:41

本文主要是介绍Redis分布式锁实现简述,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、分布式锁使用的情形如下,下图中单机锁不能保证资源互斥

一般来说分布式锁使用第三方(外部)系统来保证互斥,常见的有Zookeeper,MySQL,Redis,所有的分布式锁构建都应该注意以下几点要素

1:不能有死锁,进程不能因为出现异常就不释放锁

2:进程在锁上要有唯一标识,只能释放自己加的锁

3:保证对锁的操作是原子性的

4:锁租期

本博客主要介绍使用Redis构建分布式锁,先从简单的开始说明

1:既然是锁,那就需要使用Redis实现互斥的逻辑,使用最简单的String类型K-V格式

127.0.0.1:6379> SETNX dlock 1
(integer) 1         #进程1

127.0.0.1:6379> SETNX dlock 1
(integer) 0          #进程2

加锁成功的进程,就可以去操作被锁住的共享资源了,当操作完成后接着释放锁就可以了。

127.0.0.1:6379> DEL dlock // 释放锁
(integer) 1        #进程1释放锁

既然加锁是SETNX,解锁就可以直接DEL,这种简单的步骤大致就是这样:

 但是,这种实现方式是存在问题的:

1:拿到锁的进程1操作共享资源时(例如调用API)阻塞住了,出异常了,不能释放锁

2:进程1被kill掉了

这样的话违背了上面说的,实现分布式锁的注意事项,出现了死锁

2:要解决死锁的问题,只要设置进程对锁的使用时间就好了,简单来说直接给这个key加上过期时间就行了,这样的话就算进程死掉了锁还是能释放的

127.0.0.1:6379> SET dlock 1 EX 10 NX
OK        #进程1加锁

虽然这样确实避免了死锁的问题,但是会存在如下新的两个问题

1:进程1加锁成功,开始进行业务操作

2:进程1业务时间,超过了锁的过期时间,锁被自动释放(锁租期不够)

3:进程2加锁成功,开始操作共享资源

4:进程1操作共享资源完成,释放锁(释放了非本进程的锁)

问题1:锁租期不够

这个问题人为的估算肯定是不行的,因为无法预知进程x执行业务到底需要多少时间,估算长了浪费锁资源,短了就锁不住资源,出现了资源不互斥的问题

目前通用的解决方法是:加锁时,先设置一个过期时间,然后我们开启一个守护线程/进程,定时去检测这个锁的失效时间,如果锁快要过期了,业务还未完成,那么就自动对锁进行续期,重新设置过期时间,避免锁过期

Redisson就是使用该方式进行锁租期的续费,类似于下图

这样就可以解决问题了,避免锁提前到期产生的一系列问题

问题2:释放了非本进程的锁

这个问题主要是因为进程在释放锁的时候不知道锁的持有者是谁,这一点其实很好解决,就类似于Monitor Record那种,在加一个进程/线程标识就可以了,只要记住锁是谁持有的就行

127.0.0.1:6379> SET dlock {pid} EX 20 NX

这样在释放锁的时候只需要判断下就可以了,很方便,业务代码这么写

RBucket<Long> bucket = client.getBucket("dLock");
if (Thread.currentThread().getId() == bucket.get()){
    // todo 释放锁
}

但是,获取锁的Value和删除锁,在业务里不是原子性操作,就会导致

1:进程1执行GET,判断锁是自己的

2:进程2执行了上面的SET命令,获取到锁(发生概率比较低但是还是有可能的)

3:进程1执行DEL,却释放了客户端 2 的锁(又出现了释放别人的锁的问题

这个时候就得用Lua脚本来执行获取-删除这个业务了,Redis也可以执行Lua脚本,因为Redis在命令执行的过程中是单线程的,所以不会被其他进程中途插入执行,脚本逻辑类似于这样

if redis.call("GET",KEYS[1]) == ARGV[1]
then
    return redis.call("DEL",KEYS[1])
else
    return 0
end

这样,释放他人的锁的问题也算是解决了

现在Redis的加锁/解锁的流程已经很流畅了,解决了刚刚提出的问题,总结如下:

1:加锁:SET key {pid} EX {time} NX

2:执行业务访问资源

3:释放锁,这里使用脚本

到现在为止,对分布式锁的讲解还是停留在,非主从模式下的redis,一般来说正式环境都是使用主从模式或者是cluster模式,所以还会有新的问题产生,这个问题流到下期再介绍



这篇关于Redis分布式锁实现简述的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程