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 相关底层原理 我们就介绍到这里 具体运用我们敬请期待

相关推荐
爱学习的阿磊2 分钟前
用Python实现自动化的Web测试(Selenium)
jvm·数据库·python
@ chen10 分钟前
MySQL 存储引擎概览
数据库·mysql
橘子1314 分钟前
MySQL事务(十一)
数据库·mysql
DBA小马哥17 分钟前
Oracle兼容替换案例:某省运营商传输网管系统国产化落地实战
数据库·oracle
符哥200821 分钟前
家用智能充电桩管理系统 - MySQL 表结构参照文档
数据库·mysql
u01092727130 分钟前
高级爬虫技巧:处理JavaScript渲染(Selenium)
jvm·数据库·python
冰暮流星37 分钟前
sql语言之where in语句
数据库·sql
北极象1 小时前
PostgreSQL 16 容器主从流复制
数据库·postgresql
Test-Sunny1 小时前
【futu测试案例】性能测试中常见的问题汇总
数据库
zt1985q1 小时前
本地部署静态网站生成工具 Vuepress 并实现外部访问
运维·服务器·网络·数据库·网络协议