Redis 分布式锁

在分布式系统中,存在多进程多主机(每个服务器都是独立的进程),在此种情况下,多进程的运行情况是随机的,我们无法使用sychronized这类锁去控制多进程

因此我们就需要引入"分布式锁"

分布式锁的实现

在上面这张图中,当客户端进行买票操作时,会先查询余票,然后进行扣除,当没有加锁时,在第一个客户端进行操作查询到余票 还未扣除时,第二个客户端也进行买票操作,那么此时就会出现超卖情况

所谓的分布式锁 就是一个/一组单独的服务器程序,给其他的服务器提供"加锁"这样的服务

买票服务器在进行买票时,操作的过程中就需要先加锁

Redis上设置一个特殊的key-value

完成上述买票操作,再把这个key-value删除掉

如果其他服务器要进行买票操作,就会设置这个key-value 如果已经存在 就会加锁失败,至于是阻塞还是放弃 看具体策略

引入setnx

setnx这个指令的语义是不存在就设置,存在就出错

使用setnx确实可以得到加锁效果

针对解锁,就可以使用del命令来完成

但这样当某个服务器进行setnx 还未执行del 服务器挂了 那此时锁无法释放

设置过期时间

可以给sey的key设置过期时间 一旦时间到了就会自动删除

set ex nx 这样的命令来设置

校验id

因为我们此处分布式锁只是redis上的一个键值对,那么很有可能被误删,服务器1执行加锁,而服务器2执行了解锁

正常来说是不会的 但是代码总有bug

为了解决上述问题,就引入一点校验机制

1.给服务器编号,每个服务器有一个自己的身份标识

2.进行加锁的时候,设置key-value,key对应着要针对哪个资源加锁(比如车次),value就可以存储刚才服务器编号,标识当前锁是哪个服务器加上的

解锁时 就先查询所对应服务器编号,判定这个编号是否就是当前执行解锁的服务器编号,如果是执行del,如果不是 失败

引入lua脚本

在执行解锁过程中 由于是两步操作,先获取,后解锁

服务器很可能是多线程的 就会出现问题

使用事务可以解决上述问题 防止插队,但实践中往往使用的是lua脚本

可以使用lua编写一些逻辑,把这个脚本上传到redis服务器上,然后就可以让客户端来控制redis执行上述脚本

redis执行lua脚本的过程,也是原子的,相当于执行一条命令一样(实际上lua中可以 写对个命令)

引入看门狗

过期时间的续约问题

过期时间设置多少合适

*如果设置的短,可能业务执行逻辑还没执行完就释放锁了

*如果设置的太长,就也会导致锁释放不及时的问题

更好的方式是动态续约 往往需要服务器这边有个专门的线程 来进行 叫"看门狗"

初始时设置一个时间 动态续约 如果服务器挂掉 也不会一直持有锁 会随后释放

redlock算法

使用redis作为分布式锁,redis本身有没有可能挂呢,很有可能

哨兵模式中 当主节点加锁后挂了 从节点成为新的主节点 获取的有主节点的数据也会被加锁

但当主节点挂了时 从节点同步主节点数据有延迟,此时呢就会可能加锁失败

为了提高可用性,就使用了redlock算法

这样呢就提高了可用性

关于redis 分布式锁呢 我们就探讨到这里

至此Redis 相关底层原理 我们就介绍到这里 具体运用我们敬请期待

相关推荐
jiayou642 小时前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤1 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
初次攀爬者2 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
爱可生开源社区2 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1772 天前
《从零搭建NestJS项目》
数据库·typescript
加号33 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏3 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐3 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
百锦再3 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip
tryCbest3 天前
数据库SQL学习
数据库·sql