当前位置: 首页 > news >正文

关于redis中的分布式锁

目录

分布式锁的基础实现

引入过期时间

引入校验id

引入lua脚本

引入看门狗

redlock算法


分布式锁的基础实现

多个线程并发执行的时候,执行的先后顺序是不确定的,需要保证程序在任意执行顺序下,执行逻辑都是ok的。

在分布式系统中,每个服务器都是独立的进程,因此,之前的锁,就难以对现在分布式系统中的多个进程之间产生制约。分布式系统中,多个进程之间的执行顺序也是不确定的。

像这样的情况就需要引入分布式锁来解决上述问题。

举个例⼦: 考虑买票的场景, 现在⻋站提供了若⼲个⻋次, 每个⻋次的票数都是固定的。现在存在多个服务器节点, 都可能需要处理这个买票的逻辑: 先查询指定⻋次的余票, 如果余票 > 0, 则设置余票值 -= 1。

显然上述的场景是存在 "线程安全" 问题的, 需要使⽤锁来控制。否则就可能出现 "超卖" 的情况。

此时如何进⾏加锁呢? 我们可以在上述架构中引⼊⼀个 Redis ,作为分布式锁的管理器。给其他的服务器提供“加锁”这样的服务。(redis是一种典型的可以用来实现分布式锁的方案,但不是唯一一种)

买票服务器,在进行买票的过程中,就需要先加锁(往redis上设置一个特殊的key-value)。完成上述买票操作之后,再把这个key-value删除掉。

其他服务器买票的时候,也要去redis上设置key-value,如果发现key-value已经存在,就认为“加锁失败”。(放弃/阻塞,就看具体的实现策略了)

上述操作就可以保证,第一个服务器执行“查询 ->更新”过程中,第二个服务器不会执行“查询”。

引入过期时间

如果服务器直接掉电,进程异常终止,这样的情况会导致redis上设置的key无人删除,也就导致其他服务器无法获取到锁了。这种情况该如何处理?

可以给key设置过期时间,一旦时间到,key就会自动被删除掉了。

可以通过 set ex nx 命令来实现。

比如设置key的过期时间为1000ms,那么意味着即使出现极端情况,某个服务器挂了,没有正确释放锁,这个锁最多保持1000ms,也就会自动释放了。

引入校验id

所谓的加锁,就是给redis上设置一个key-value。

所谓的解锁,就是给redis上这个key-value删除掉。

是否可能出现服务器1执行了加锁,服务器2执行了解锁

有可能的。服务器有可能不小心执行到了解锁操作,因此就可能进一步给整个系统带来更严重的问题。

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

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

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

3.后续在解锁的时候,就可以进行校验了。(解锁的时候,先查询一下这个锁对应的服务器编号。然后判定一下这个编号是否就是当前解锁的服务器的编号,如果是,才能真正执行del。如果不是,就失败)

引入lua脚本

在解锁的时候,先查询判定,再进行del。此处两步操作(不是原子的),就可能会出现问题。

一个服务器内部,也可能是多线程的。此时,就可能同一个服务器,两个线程都在执行上述解锁操作。

在线程A执行完DEL之后,B执行DEL之前。服务器2的线程C正好要执行加锁(set),此时由于A已经把锁释放了,C的加锁是能够成功的。因为在线程B查询判定的时候,redis服务器已经判定这次请求来源于一个服务器了。但是紧接着,线程B DEL 就到来了。就把刚刚服务器2的加锁操作给解锁了。

可以使用lua脚本来解决上述问题。

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

redis执行脚本的过程,也是原子的。相当于执行一条命令一样。

使⽤ Lua 脚本完成上述解锁功能:

if redis.call('get',KEYS[1]) == ARGV[1] then
   return redis.call('del',KEYS[1])
else
   return 0
end;

引入看门狗

在加锁的时候,key的过期时间设定多长合适?

如果设置的短,可能在你的业务还执行完,就释放锁了。如果设置的太长,也会导致"锁释放不及时"问题。

更好的方式,是“动态续约”。初始情况下,设置一个过期时间(比如1s)就提前在还剩300ms(不一定,可以灵活调整)的时候,如果当前任务还没执行完,就把过期时间再续1s。等到时间又快到了,任务还没执行完,就再续。

如果服务器,中途崩溃了,自然就没人负责续约了,此时,锁就能在较短的时间内被自动释放。

动态续约这样的行为往往需要一个专门的线程,负责续约这个事情。称为“看门狗”。

redlock算法

使用redis作为分布式锁,redis本身有没有可能挂了呢? 当然有可能。

要想保证“高可用”就需要通过这样一系列的“预案演习”。

进行加锁,就是把key设置到主节点上,如果主节点挂了,有哨兵自动的把从节点升级成主节点,进一步的保证刚才的锁仍然可用。

但是主节点和从节点之间的数据同步,是存在延时的。可能主节点收到了set请求,还没来得及同步给从节点,主节点就先挂了。即使从节点升级成了主节点。但是,刚才的加锁对应的数据,也是不存在的。

Redlock 算法:

引⼊⼀组 Redis 节点。其中每⼀组 Redis 节点都包含⼀个主节点和若⼲从节点. 并且组和组之间存
储的数据都是⼀致的,相互之间是 "备份" 关系。

此处加锁,就是按照一定的顺序,针对这些组redis都进行加锁操作。如果某个节点挂了,继续给下一个加锁即可。

如果写入key成功的节点个数超过总数的一半,就视为加锁成功。

同理,进行解锁的时候,也会把上述节点都设置一遍。

以上,关于redis的分布式锁,希望对你有所帮助。

相关文章:

  • VUE+element 在组件内有多个el-dialog同时打开时,遮罩会叠加
  • IntelliJ IDEA 中 Git 高频问题与操作详解|新手避坑指南
  • 移动最小二乘法(Moving Least Squares, MLS)原理和c++实现
  • 网络空间安全(36)数据库权限提升获取webshell思路总结
  • Arduino示例代码讲解:Melody 旋律
  • 虚拟地址空间(下)进程地址空间(上)
  • Go语言--安装和环境搭配
  • 地球物理测量学笔记 :分布式声学传感(DAS)
  • linux之 内存管理(1)-armv8 内核启动页表建立过程
  • 【资料分享】通信技术文档汇总(20250319更新)
  • 通过C#脚本更改材质球的参数
  • 集成学习之随机森林
  • 车载以太网网络测试-17【传输层-TCP】
  • 7种寻址方式
  • Elasticsearch 在航空行业:数据管理的游戏规则改变者
  • 蓝桥与力扣刷题(蓝桥 数列求值)
  • 隐私权案件如何办理?公众人物隐私权为何受限?
  • 图莫斯TOOMOSS上位机TCANLINPro使用CAN UDS功能时 编写、加载27服务dll解锁算法文件
  • Spring Framework 中 BeanDefinition 是什么
  • 群体智能优化算法-牛顿-拉夫逊优化算法(Newton-Raphson-Based Optimizer, NRBO,含Matlab源代码)
  • 杭州打造商业航天全产业链,请看《浪尖周报》第22期
  • 凝聚多方力量,中国农科院油菜产业专家团部署单产提升新任务
  • 2025上海浪琴环球马术冠军赛开赛在即,首批赛马今晨抵沪
  • 伤者升至80人,伊朗港口爆炸源头或为“危险品和化学品仓库”
  • 政治局会议深读|首提“持续巩固房地产市场稳定态势”,楼市政策还有哪些优化空间
  • 公安部知识产权犯罪侦查局:侦破盗录传播春节档院线电影刑案25起