Redis典型应用之分布式锁

目录

前言

 分布式锁的基础实现

 引入过期时间:

 引入校验ID:

引入lua

lua的简介:

引入看门狗 (watch dog)

 引入Redlock算法


前言

在一个分布式系统中,也会涉及到多个节点同时去访问一个公共资源的时候,此时就需要通过锁来做互斥控制,避免出现类似于“线程安全”的问题~~

本质上来说就是使用一个公共的服务器,用来记录加锁状态

当然这个服务器也可以是Redis,也可以是其他的组件(MySQL、ZooKeeper等),自己手搓也行

 分布式锁的基础实现

其实就是通过一个键值对来标识锁的状态

例如:买票的时候,存在多个能够购票的软件(12306、携程等)但是票的总数是固定的,所以我们都需要先查询该票的余票是否大于0,如果成立那么票数--

但是上述的情况会出现“线程安全”问题(访问临界资源)

在上述的场景的时候就会出现“超卖”的现象~~

可以在购票服务器中加一个Redis来作为分布式锁的管理器

 

此时如果买票服务器尝试买票,就需要先访问Redis,在Redis上设置一个键值对。比如key就是车次,value就随意

如果当前设置成功,就是为当前没有节点对001车次加锁,那么就可以对数据库进行写操作,操作完成之后再把Redis上的键值对给删除掉

如果在买票服务器1买001车次的票的时候, 买票服务器2也要买001车次的票,此时买票服务器2也会想向Redis中写入key 为 001的键值对,但是此时该key已经存在,那么就会设置失败,那么我们就认为此时其他服务器持有锁,那么买票服务器2就应该等待或放弃~~

Redis提供了setnx操作,即:key不存在就设置,存在直接失败

看起来这样就已经实现了分布式锁了吗?? 

 如果此时买票服务器1宕机了怎么办,话句话说,我忘记给del这个key了!!

 引入过期时间:

为了解决上述的问题,我们可以对key引入一个过期时间,即这个锁有一个默认释放形式

注意:此处的过期时间的设置务必在设置锁的同时设置上! 

 使用set ex nx 的方式,在设置锁的时候设置上过期时间,不要分成set 与 expire 两个指令~~

这样已经大致完善了分布式锁的安全使用,但我们仍要考虑一些特殊情况~~

即购票服务器2的失误操作,将redis中已存在的key删除了~~

 引入校验ID:

为了解决上述的问题,可以引入校验ID 

即设置key的时候对其value的值设置成为服务器的编号,比如:key:"001" , value:"服务器1"

这样就可以在删除key的时候检测一下value是否对应当前执行删除操作的服务器 

 那么伪代码应该如下:

String key = [要加锁的资源 id];
String serverId = [服务器的编号];// 加锁, 设置过期时间为 10s
redis.set(key, serverId, "NX", "EX", "10s");// 执⾏各种业务逻辑
// ...// 解锁, 删除 key. 但是删除前要检验下 serverId 是否匹配.
if (redis.get(key) == serverId) {redis.del(key);
}

很明显此时get和del这两步操作不是原子的,即使有过期时间也不应该就这样,过期时间只是最后防线 

 

引入lua

 为了使解锁操作原子,可以使用Redis支持的Lua脚本功能

lua的简介:

Lua也是一门编程语言,语法类似JS,是一个动态弱类型语言,Lua的解释器一般用C语言实现,Lua的语法精炼速度快,解释器轻量(200K左右)

因此Lua经常作为其他程序的内嵌脚本语言,Redis本身就支持Lua作为内嵌脚本

使用Lua脚本完成上述的解锁功能

if redis.call('get',KEYS[1]) == ARGV[1] thenreturn redis.call('del',KEYS[1])
elsereturn 0
end;

 上述代码可以编写成一个.lua后缀的文件,由redis-cli 或者 redis-plus-plus 或者jedis 等客户端加载,并发送给Redis服务器,由Redis服务器来执行这段逻辑

一个Lua脚本会被Redis服务器以原子的方式来执行

 


引入看门狗 (watch dog)

 上述方案仍然存在一个重要问题:在过期时间内我们的服务仍未执行完成,也就是事没办完你把锁给解了

那么是不是直接加长我们的过期时间就可以了么?

如果这样,服务器1真挂了的话这个锁会僵住很长一段时间,不合理的,只能动态调整~~

所谓的watch dog ,本质就是在加锁的服务器上的一个单独的线程,通过对这个线程的加锁过期时间进行“续费”

举个例子:

初始情况下设置过期时间为10s.同时设定看⻔狗线程每隔 3s 检测⼀次.
那么当3s时间到的时候,看⻔狗就会判定当前任务是否完成

  • 如果任务已经完成,则直接通过 lua 脚本的⽅式,释放锁(删除key)
  • 如果任务未完成,则把过期时间重写设置为10s

 

 引入Redlock算法

 实践中的 Redis ⼀般是以集群的⽅式部署的(⾄少是主从的形式,⽽不是单机).

 

例如:

服务器1向master节点进⾏加锁操作.这个写⼊key的过程刚刚完成,master挂了;slave节点升级成了新的master节点.但是由于刚才写⼊的这个key尚未来得及同步给slave呢,此时就相当于 服务器1 的加锁操作形同虚设了,服务器2仍然可以进⾏加锁(即给新的 master 写⼊ key. 因为新的 master 不包含刚才的 key)

 为了解决这个问题,Redis提出了Redlock算法

引入一组Redis节点,其中每一组Redis节点都包含一个主节点和若干个从节点,并且组与组之间存储的数据都是一致的,相互之间是“备份关系”

加锁的时候,按照一定顺序,写多个master节点,在写锁的时候就需要设定“超时时间”。比如30ms。如果超过了30ms没有成功,就视为加锁失败

 

| 当加锁成功的节点数超过总结点数的一半,才视为加锁成功

| 同理,释放锁的时候,也需要把所有节点都进⾏解锁操作.(即使是之前超时的节点,也要尝试解锁,尽量保证逻辑严密).

在分布式系统中,不能让一台机器" 独断专行 ", 不能过度相信这一台机器不会宕机,最终加锁成功的结论就是“少数服从多数”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/479578.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS API for JavaScript 4.X 本地部署(js,字体)

0 目录(4.19) /4.19/ 1 修改文件 1.1 init.js 编辑器打开/4.19/init.js搜索文本[HOSTNAME_AND_PATH_TO_JSAPI],然后将其连同前面的https://替换为http://ip地址/4.19,可以是localhost,只能本机引用 替换后&#xff…

Selenium 自动化测试—如何搭建自动化测试环境

🍅 视频学习:文末有免费的配套视频可观看 🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 最近也有很多人私下问我,selenium学习难吗,基础入门的学习内容很多是3以前…

【linux】体系结构和os管理

冯诺依曼体系结构 输入单元:包括键盘, 鼠标,扫描仪, 写板等 中央处理器(CPU):含有运算器和控制器等 输出单元:显示器,打印机等 这里的存储器指的是内存 三者是相互连接的,设备之间会进行数据的来回拷贝&am…

社区店经营全攻略:如何选址、运营并打造火爆生意?

随着电商的兴起,实体店的经营面临着越来越多的挑战。然而,社区店依然具有独特的优势,如便捷的地理位置、与消费者的紧密互动等。 作为在社区店开鲜奶吧5年的创业者,我深有感触,那么这篇文章将为你提供最有价值的干货信…

计算机设计大赛 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满…

深入浅出JVM(一)之Hotspot虚拟机中的对象

本篇文章思维导图 对象的创建 对象的创建可以分为五个步骤:检查类加载,分配内存,初始化零值,设置对象头,执行实例构造器 类加载检查 HotSpot虚拟机遇到一条new指令,会先检查能否在常量池中定位到这个类的符号引用,检查这个类是否类加载过 没有类加载过就去类加载类加载过就进…

基于Java+SpringBoot的旅游路线规划系统(源码+论文)

文章目录 目录 文章目录 前言 一、功能设计 二、功能实现 1.1 前端首页模块的实现 1.2 景点新闻 1.3 景点在线预订 1.4 酒店在线预订 1.5 管理员景点管理 1.6 管理员旅游线路管理 1.7 酒店信息管理 三、库表设计 前言 随着我国的经济的不断发展,现在的一些热门的景…

【C++】类与对象(构造函数、析构函数、拷贝构造函数、常引用)

🌈个人主页:秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343🔥 系列专栏:http://t.csdnimg.cn/eCa5z 目录 类的6个默认成员函数 构造函数 特性 析构函数 特性 析构的顺序 拷贝构造函数 特性 常引用 前言 &…

HBase 进阶

参考来源: B站尚硅谷HBase2.x 目录 Master 架构RegionServer 架构写流程MemStore Flush读流程HFile 结构读流程合并读取数据优化 StoreFile CompactionRegion Split预分区(自定义分区)系统拆分 Master 架构 Master详细架构 1)Meta 表格介…

光芒绽放:妙用“GLAD原则”打造标准的数据可视化图表

光芒绽放:妙用“GLAD原则”打造标准的数据可视化图表 文章目录 光芒绽放:妙用“GLAD原则”打造标准的数据可视化图表前言一、可视化工具有哪些?二、那如何做出正确可视化图表 ?GLAD原则1.G原则2.L原则3.A原则4.D原则 三、总结最后…

模式匹配这么好,Java语法里有吗?

这篇文章我们借助新版Java来理解模式匹配,Rust版的模式匹配稍后就端上来,各位先尝尝Java这杯老咖啡还香不香😄。 什么是模式匹配? 下图直观的表达了模式匹配的概念。 所谓模式类似上图中木盒的各种形状的洞洞,我们…

单片机学习笔记---红外遥控(外部中断)

目录 红外遥控简介 硬件电路 基本发送与接收 NEC编码​​​​​​​ 遥控器键码 复习外部中断和定时器 红外遥控简介 红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出 通信方式:单工…