Redis分布式锁

Redis分布式锁

文章目录

分布式锁是什么

锁我们可以理解为对某项资源使用权限的管理,通常使用锁来控制共享资源,比如一个进程内多个线程竞争一个资源的使用权限,解决方式其中就含有加锁。

而分布式锁,就是分布式场景下的锁,多台不同的机器上的进程去竞争同一个资源,需要加分布式锁。

分布式锁的特性

1.互斥性:只让一个竞争者持有锁

2.安全性:避免锁因为异常永久不被释放,使用过期时间兜底

3.对称性:同一个锁,必须由同一个竞争者加锁和释放锁

4.可靠性:一定程度的异常处理能力、容灾能力

Redis实现分布式锁

版本一:easy版本

  • setnx key value

利用Redis的setnx命令,将key设置为value,并且返回1;如果key存在,不会创建锁,返回0

流程:通过setnx加锁,加锁之后其他服务无法加锁,用完之后再通过delete解锁

版本二:支持过期时间

如果获取锁的服务挂了,那么锁就一直不被释放,后面的服务无法获取被锁着的资源,所以我们加一个超时时间来兜底。

使用Redis命令,给键加上过期时间即可。

set key value nx ex seconds

ex:增加了过期时间,seconds:设置的过期时间是多久

但是这又有一个新的问题,如果服务A的业务时间比较长,此时锁过期后,服务B获取了锁,然后服务A业务结束后释放了该锁(服务B业务此时还没结束)。

基于这个场景,我们又可以进一步优化分布式锁。

版本三:支持owner

分布式锁需要满足,谁申请的锁谁释放的原则。

同样的,使用Redis命令:set key 业务id nx ex second

在释放锁前,get锁进行判断即可。

另一个方法,也可以启动一个看门狗(go启动一个 gorountine),过期前去刷新过期时间即可。

版本四:lua

其实完整的流程是对的,但是现在还有一个问题:原子性

检查锁,再释放锁,这些操作不是原子的;可能锁获取时还是自己的,删除时已经是别人的了(比如你持有的锁过期了,被别人获取到了)。

使用Redis特性,整合原子操作的lua;Redis+Lua,可以专门解决原子性问题。

有了Lua,Redis才能真正的在分布式锁场景下被使用。

到了版本四,我们已经满足了分布式锁的前三个特性:对称性、安全性、互斥性。

可靠性如何保证

之前都是基于单机的,但是如果Redis挂了,那么就不能获取锁了。

解决方法:主从容灾和多级部署

主从容灾

给Redis配置从节点,当主节点挂掉,可以用从节点暂时顶包。

但是主从切换需要人工参与,提高了人力成本。但是Redis已经有了解决方案,使用哨兵模式,节点灵活自动切换,不需要人工参与。

尽管这种方法一定的程度上解决了单点的容灾问题,但是由于同步时延,Slave会损失部分数据,分布式锁可能会失效,可能会导致短暂的多个机器获取到执行权限。

所以有一个更可靠的办法。

多机部署

对一致性要求更高可以使用多机部署,使用Redis的RedLock。

大概的思路是:通常是N个机器(N一般为奇数),达到一半以上同意加锁才算加锁成功。

加锁流程一般为(以N=5为例):

1.向5个Redis申请加锁

2.超过一半(3个)同意,就可以获取到锁;反之,向每个Redis发送解锁命令

3.由于向5个Redis发送请求,会有一定的时耗,所以锁持有时间应该需要减去请求时间。如果剩余时间为0,那就是获取锁失败

4.使用完锁后,向5个Redis发送解锁请求

这种方案是一般比较成熟的方法了,最后我们再给每个Redis配上哨兵模式就增强了可靠性。

但是这就一定能保证可靠性吗?

不足分析

NPC问题

1.网络时延(Network Delay):RedLock的锁剩余持有时间,需要减去请求时间,可以一定程度的解决网络延迟问题。

2.进程暂停(Process Pause):如果进程获取锁后发生了GC,但是锁已经过期了,那么就会有两个进程获取到同一个锁。

3.时钟漂移(Clock Drift):如果服务A通过RedLock方案获取了锁,但是机器都发送了时钟漂移,锁瞬间过期了,那么又会有两个进程获取到同一个锁。

相关推荐
bing_1584 分钟前
在 Spring Boot 项目中,如何进行高效的数据库 Schema 设计?
数据库·spring boot·后端·数据库schema设计
s_little_monster10 分钟前
【Linux】线程互斥之线程加锁
linux·运维·经验分享·redis·笔记·学习·学习方法
听雪楼主.21 分钟前
Oracle补丁安装工具opatch更新报错处理
数据库·oracle
不吃元西22 分钟前
对于客户端数据存储方案——SQLite的思考
数据库·sqlite
rgb0f024 分钟前
MySQL视图相关
数据库·mysql·oracle
编程、小哥哥27 分钟前
oracle值sql记录
数据库·sql·oracle
三千花灯33 分钟前
jmeter提取返回值到文件
数据库·jmeter
遥夜人间34 分钟前
Redis之缓存更新策略
redis·缓存
萧离1951 小时前
超细的Linux安装minio教学
数据库
小吕学编程1 小时前
基于Canal+Spring Boot+Kafka的MySQL数据变更实时监听实战指南
数据库·后端·mysql·spring·kafka