【Redis】Redis实现分布式锁

分布式锁

分布式锁是一种在分布式系统中实现同步机制的技术。它允许多个进程或节点在访问共享资源时进行同步,以确保它们按照预期的顺序执行。

这篇文章使用Redis来分布式锁,通俗的来说,分布式锁本质上要实现的目标就是在Redis里面占一个"茅坑",当别的进程也要来占时,发现已经有人蹲在那里了,就只好放弃或者稍后重试。

接下来我们来循序渐进的实现一个成功的分布式锁。

一、使用setnx指令

Redis分布式锁一般使用setnx(setifnotexists)指令,只允许被一个客户端占坑。先来先占,用完了,再调用del指令释放"茅坑"。

shell 复制代码
setnx lock:codehole true

...do something critical ...

del lock:codehole

简单的使用setnx指令肯定会出现一些问题

问题一:如果逻辑执行到中间出现异常了,可能会导致del指令没有被调用,这样就会陷入死锁,锁永远得不到释放。

我们首先想到的肯定是:"加一个过期时间就行了"。那我们接着往下看。

二、使用setnx+expire指令

给锁加上过期时间后,如果程序执行到中间出现异常或超时了,到了过期时间后就自动释放锁。

shell 复制代码
setnx lock:codehole true
expire lock:codehole 5

... do something critical ...
del lock:codehole

问题二:如果在setnx和expire之间服务器进程突然挂掉了,可能是因为机器掉电或者是被人杀掉的,就会导致expire得不到执行,也会造成死锁。

解决方案: 使用Redis中setnx和expire组合原子命令。

三、使用setnx和expire组合原子命令

为了解决这个问题,Redis在2.8版本中加入了set指令的扩展参数,使得setnx和expire指令可以一起执行,解决了这个问题。

shell 复制代码
set lock:codehole true ex 5 nx

... do something crutical ...

del lock:codehole

问题三:释放锁错乱问题,当前锁可能释放的不是自己的锁。

如果在加锁和释放锁之间的逻辑执行的太长,以至于超出了锁的超时限制,就会出现问题。因为这时候锁过期了,第二个线程重新持有了这把锁,但是紧接着第一个线程执行完了业务逻辑,就把锁给释放了。

场景:如果业务逻辑的执行时间是7s。执行流程如下

  1. index1业务逻辑没执行完,3秒后锁被自动释放。

  2. index2获取到锁,执行业务逻辑,3秒后锁被自动释放。

  3. index3获取到锁,执行业务逻辑

  4. index1业务逻辑执行完成,开始调用del释放锁,这时释放的是index3的锁,导致index3的业务只执行1s就被别人释放。

最终等于没锁的情况。

解决方案:获取锁时,设置一个指定的唯一值value(例如:雪花Id),释放前获取这个锁,判断是否是自己的锁。

四、指定唯一值value

获取锁时,设置一个自己的唯一值,释放锁之前先判断这个value唯一值是否是自己的锁,如果是自己的锁才可以释放。

shell 复制代码
set lock:codehole 唯一值 ex 5 nx

... do something crutical ...

释放之前判断唯一值是否是自己加锁前的唯一值
del lock:codehole

问题:判断加删除操作缺乏原子性,也会造成问题。

场景:

  1. index1执行删除时,查询到的lock值确实和uuid相等

  2. index1执行删除前,lock刚好过期时间已到,被redis自动释放,在redis中没有了lock,没有了锁。

  3. index2获取了lock,index2线程获取到了cpu的资源,开始执行方法

  4. index1执行删除,此时会把index2的lock删除。index1 因为已经在方法中了,所以不需要重新上锁。index1有执行的权限。index1已经比较完成了,这个时候,开始执行删除的index2的锁!

解决方案:使用lua脚本,lua脚本可以保证连续多个指令的原子性执行。

五、使用Redis+Lua脚本

使用 Lua 脚本来处理,Lua 脚本可以保证连续多个指令的原子性执行。

go 复制代码
if redis.call("get",KEYS[1]) == ARGV[1] then
 return redis.call("del",KEYS[1])
else
 return 0

最终,分布式锁的最终版本就是Redis中setnx 和 Lua脚本了。

相关推荐
Elastic 中国社区官方博客3 分钟前
超越相似名称:Elasticsearch semantic text 如何在简洁、高效、集成方面超越 OpenSearch semantic 字段
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
Warren9817 分钟前
Java Record 类 — 简化不可变对象的写法
java·开发语言·jvm·分布式·算法·mybatis·dubbo
头发还在的女程序员2 小时前
ThinkPHP+Mysql 灵活用工小程序-技术深度解析与实践指南
数据库·mysql·小程序
꒰ঌ 安卓开发໒꒱2 小时前
SQL Server安全删除数据并释放空间的技术方案
数据库·安全·oracle
crossoverJie3 小时前
在多语言的分布式系统中如何传递 Trace 信息
分布式·后端·开源
用户848508146903 小时前
SurrealDB 快速上手教程
数据库·后端
kura_tsuki3 小时前
[Oracle数据库] ORACLE的用户维护和权限操作
数据库·oracle
一个儒雅随和的男子3 小时前
Seata深度剖析:微服务分布式事务解决方案
分布式·微服务
十年一梦实验室3 小时前
【IgH EtherCAT】 一个硬实时 EtherCAT 主站示例基于RTAI/LXRT并实现了分布式时钟 (DC) 同步功能
分布式
柏峰电子4 小时前
分布式光伏气象站:为光伏电站的 “气象感知眼”
分布式