【Redis】Redis 分布式锁

概述

在单体项目中,我们处理多线程同时操作某一处代码块或者变量时就使用 Synchronized 或者 Lock 锁去保证数据的安全性,但是,现在我们基本上都是使用微服务,当我们把服务部署到多个进程中去,这时候使用 Synchronized 或者 Lock 锁就没办法保证数据的安全性,这时候就需要用到分布式锁。

想要实现分布式锁,需要借助一个外部系统,所有进程都去这个系统上申请加锁,而这个外部系统,必须要实现互斥的能力,即两个请求同时进来,只会给一个进程返回成功,另一个返回失败(或等待)。

在这里插入图片描述


Redis 实现分布式锁

使用 SETNX 命令,这个命令表示SET if Not eXists,即如果 key 不存在,才会设置它的值,否则什么也不做,两个客户端进程可以执行这个命令,达到互斥,就可以实现一个分布式锁。

加锁

客户端 1 申请加锁,加锁成功:

127.0.0.1:6379> SETNX lock 1
(integer) 1     // 客户端1,加锁成功

客户端 2 申请加锁,因为它后到达,加锁失败:

127.0.0.1:6379> SETNX lock 1
(integer) 0     // 客户端2,加锁失败

释放锁

此时,加锁成功的客户端,就可以去操作共享资源,例如,修改 MySQL 的某一行数据,或者调用一个 API 请求。
操作完成后,还要及时释放锁,给后来者让出操作共享资源的机会,使用 DEL 命令删除这个 key 即可释放分布式锁:

127.0.0.1:6379> DEL lock // 释放锁
(integer) 1

这个逻辑非常简单,整体的路程就是这样:
在这里插入图片描述

死锁

但是,它存在一个很大的问题,当客户端 1 拿到锁后,如果发生下面的场景,就会造成死锁
1、程序处理业务逻辑异常,没及时释放锁;
2、进程挂了,没机会释放锁;
这时,这个客户端就会一直占用这个锁,而其它客户端就拿不到这把锁了。

我们很容易想到的方案是,在申请锁时,给这把锁设置一个到期时间,过了这个到期时间,就把锁释放掉。
在 Redis 中实现时,就是给这个 key 设置一个过期时间。这里我们假设,操作共享资源的时间不会超过 10s,那么在加锁时,给这个 key 设置 10s 过期即可,在 Redis 2.6.12 之后,Redis 扩展了 SET 命令的参数,用一条命令就可以实现加锁的时候同时给锁加上时间,来避免死锁的发生,命令如下
EX 后面跟的是秒,如果想要设置毫秒的话就用 PX

# 设置秒级的分布式锁
127.0.0.1:6379> SET lock 1 EX 10 NX
OK




End


猜你喜欢

转载自blog.csdn.net/weixin_43657300/article/details/128315977