【Redis】如何利用 Redis 实现一个分布式锁?

👏大家好!我是和风coding,希望我的文章能给你带来帮助!

🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦

📝点击 我的主页 还可以看到和风的其他内容噢,更多内容等你来探索!

📕欢迎参观我的个人网站:Gentlewind

何时需要分布式锁?

在分布式的环境下,当多个服务器并发修改同一个资源时,为了避免竞争就需要使用分布式锁。那为什么不能使用Java自带的锁呢?因为Java中的锁是面向多线程设计的,它只局限于当前的JRE环境。而多个server实际上是多进程,是不同的JRE环境,所以Java自带的锁机制在这个场景下是无效的。

如何实现分布式锁?

采用Redis实现分布式锁,就是在Redis里存一份代表锁的数据,通常用字符串即可。实现分布式锁的思路,以及优化的过程如下:

🔎实现过程:

  1. 加锁

第一版,这种方式的缺点是容易产生死锁,因为客户端有可能忘记解锁,或者解锁失败。

setnx key value

第二版,给锁增加了过期时间,避免出现死锁。但这两个命令不是原子的,第二步可能会失败,依然无法避免死锁问题。

setnx key value expire key seconds

第三版,通过"set...nx..."命令,将加锁、过期命令编排到一起,它们是原子操作了,可以避免死锁。

set key value nx ex seconds

  1. 解锁

解锁就是删除代表锁的那份数据。

del key

  1. 问题

看起来已经很完美了,但实际上还有隐患,如下图。进程A在任务没有执行完毕时,锁已经到期被释放了。等进程A的任务执行结束后,它依然会尝试释放锁,因为它的代码逻辑就是任务结束后释放锁。但是,它的锁早已自动释放过了,它此时释放的可能是其他线程的锁。

想要解决这个问题,我们需要解决两件事情:

  1. 在加锁时就要给锁设置一个标识,进程要记住这个标识。当进程解锁的时候,要进行判断,是自己持有的锁才能释放,否则不能释放。可以为key赋一个随机值,来充当进程的标识。
  2. 解锁时要先判断、再释放,这两步需要保证原子性,否则第二步失败的话,就会出现死锁。而获取和删除命令不是原子的,这就需要采用Lua脚本,通过Lua脚本将两个命令编排在一起,而整个Lua脚本的执行是原子的。

按照以上思路,优化后的命令如下:

java 复制代码
# 加锁 set key random-value nx ex seconds   
# 解锁 if redis.call("get",KEYS[1]) == ARGV[1] then     
return redis.call("del",KEYS[1]) else     return 0 end

基于 RedLock 算法的分布式锁

在单个主节点的架构上实现分布式锁,是无法保证高可用的。若要保证分布式锁的高可用,则可以采用多个节点的实现方案。这种方案有很多,而Redis的官方给出的建议是采用RedLock算法的实现方案。该算法基于多个Redis节点,它的基本逻辑如下:

  • 这些节点相互独立,不存在主从复制或者集群协调机制;
  • 加锁:以相同的KEY向N个实例加锁,只要超过一半节点成功,则认定加锁成功;
  • 解锁:向所有的实例发送DEL命令,进行解锁;

我们可以自己实现该算法,也可以直接使用Redisson框架。

相关推荐
VortMall11 分钟前
『平台去经营化』平台治理能力全新重构|VortMall微服务商城系统v1.3.10
java·大数据·微服务·商城系统·开源商城·vortmall·去经营化
胖大和尚15 分钟前
C++ 多线程编程的实现方式
c++·thread
吴声子夜歌22 分钟前
Redis 3.x——集群故障转移
java·数据库·redis·集群
名不经传的养虾人25 分钟前
从0到1:企业级AI项目迭代日记 Vol.71|系统显示正常,但实际上什么都没发生
数据库·人工智能·ai编程·ai工作流·企业ai
尽兴-28 分钟前
企业数据库选型与演进:Oracle、达梦、MySQL 与分库分表实践
数据库·mysql·oracle·分库分表
Java面试题总结31 分钟前
mybatis插件
java·tomcat·mybatis
JaneConan32 分钟前
鸿蒙 ArkUI 深水区:@Watch 和 @Observed,状态变了「自动跑」+ 嵌套对象「深层重绘」
开发语言·后端·ui·harmonyos
用户40966601317511 小时前
学生成绩查询系统:从 5000 人到 50 万人,你会怎么设计它?
后端
hunterandroid1 小时前
[鸿蒙从零到一] ArkUI 组件化实战:构建可复用、可组合的自定义组件
前端·华为·架构
你为她披上外套时我正站在窗外1 小时前
5 分钟玩转 siwi-download:CLI + Rust 库上手指南
后端