千家信息网

Redis分布式锁怎么应用

发表于:2024-11-30 作者:千家信息网编辑
千家信息网最后更新 2024年11月30日,这篇文章主要讲解了"Redis分布式锁怎么应用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Redis分布式锁怎么应用"吧!分布式锁在单进程应用中,当
千家信息网最后更新 2024年11月30日Redis分布式锁怎么应用

这篇文章主要讲解了"Redis分布式锁怎么应用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Redis分布式锁怎么应用"吧!

分布式锁

在单进程应用中,当一段代码同一时间内只能由一个线程执行时,

多线程下可能会出错,例如两个线程同时对一个数字做累加,两个线程同时拿到了该数字,例如40,一个线程加了10,一个线程加了20,正确结果应该是70,

但由于两个线程在自己的内存中一个算出的是50,一个算出的是60,此时二者都将自己的结果往该数字原本的地方写(保存),

这时候,肯定会有一个线程的值会被覆盖,因为读取->计算->保存 并不是原子操作(原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就会一直运行结束,中间不会有任何线程切换),

也就是说最终的结果要么是50,要么是60,而不可能是70(出现并发或并行的情况下,这种情况大概率会发生),

单进程应用发生这种情况时,可以由程序提供的锁语义直接上锁(例如java中的sychornized)保证该段代码只会被一个线程执行,按照顺序来进行,结果将是正确的。

在分布式应用中,由于一台机器上可能跑着相同的应用进程,或者在不同的机器上跑着,原本程序自带的语义锁已经无法起到作用,

因为相同的代码可能是在不同的机器、进程中执行,所以此时需要一个能够让不同机器、进程中,相同的应用代码执行到同一段代码时,也能够按照顺序执行(或者同一时间内只有一个线程能够执行),

这就需要用到中间件来协调,可以实现分布式锁的中间件有很多,redis就是其中一个。

redis实现分布式锁的原理

redis中分布式锁的原理其实就是在redis当中设置一个值(当然要保证分布式应用连的都是同一个redis,以这个redis作为中间点,否则当然是没用的),这个值只能由一个线程来存放,当其他线程(或者不同机器上的进程)也来存放时,发现这个值已经存在了,就说明此时已经有人在用这把锁了,这时候要么进行重试等待,要么进行放弃。

设置一般使用 SETNX (set if not exists) 指令,如果该值没有,则进行设置,有了则不设置,这就是拿锁的关键了,当拿到锁的人执行处理完毕后,再调用 DEL 执行进行锁的释放。

死锁问题

使用 SETNX 和 DEL 实现了分布式锁,但是有一种情况,如果一个线程进行了 SETNX 拿到锁成功后,突然这个线程因为某种原因崩溃了,导致没有进行 DEL 释放锁,

那么此时,将会导致其他所有的应用都再也没办法拿到这把锁,也就是 死锁 ,这个问题的解决方式是将锁设置一个有效期,到了有效期之后该锁将被自动释放,

使用 EXPIRE 可以给锁设置一个有效期,如下

SETNX LOCK-KEY-NAME trueEXPIRE LOCK-KEY-NAME 5

但是还有一个问题,因为 SETNX 和 EXPIRE 是分为两个指令执行的,这中间依然有可能出现 SETNX 执行完毕后,由于认为或者机器、程序发生的故障 导致 EXPIRE 没有执行成功,此时还是有可能会发生死锁,

事务能不能解决这个问题?

NO,因为 EXPIRE 是依赖 SETNX 的执行结果执行的,只有 SETNX 成功后,才能进行 EXPIRE,否则是不可以执行的,事务里并没有 if else 的分支逻辑,要么全部执行,要么一个都不执行。

在 redis2.8 的版本中,引入了set指令的拓展参数,可以让 SETNX 和 EXPIRE 同时执行(原子),解决了超时问题,

SET LOCK-KEY-NAME true ex 5 nx

超时问题

上面虽然说到利用给锁设置过期时间解决可能会发生的死锁问题,但是万一我的程序代码执行时间超过了设置的过期时间,这时候锁自动释放了,但是我的代码还没执行完毕,其他人又进行执行了,导致结果出错怎么办?

在一般的开发场景中,我们会尽量将锁的时间设置的长一些,例如60s,一般应用程序在60s内都能执行完毕,但是怕就怕的是较真,如果60s内也执行不完怎么办?

此时可以使用一种续期的方案,就是当程序在执行过程中,不断的判断锁是否快要过期,代码是否执行完毕,如果快过期了没有执行完毕,就将这把锁进行续期,保证锁不会被自动释放,直到我们的代码执行完毕为止,这种方案在java中由一个叫做 redisson 的框架实现了,可以直接引入使用。

锁误放问题

在锁的使用过程中,很有可能出现其他应用没有拿到锁,但是也执行了 DEL 指令,将我们正在执行中的程序的锁释放了,导致其他地方拿到锁,进入代码段开始执行,

这里的解决方式是,在SETNX的时候,可以将value设置成一个随机生成并全局唯一的一串数字或字符,该线程一直持有字符,在释放锁的时候,将字符与锁中的字符进行比对,如果匹配,则可以进行释放锁,如果不匹配,说明是其他人误放,此时拒绝释放,

但是判断字符是否相同与释放锁并不是原子操作,redis也并不提供这么一种命令,所以我们考虑使用lua脚本执行这几步操作(redisson也实现了),

最重要的一点是,程序中使用释放锁的入口一定要统一,万一有的应用程序不使用上面所述的方法释放,直接使用 DEL ,那么上面说的方案就没用了(笔者为了测试,直接用DEL释放过)。

可重入性

可重入性是指线程在持有锁的情况下,再次请求加锁,如果一个锁支持同一个线程的多次加锁,那么这个锁就是可重入的,Java中的 ReentrantLock 就是可重入锁,大致的原理就是每次获取到锁后对一个数字进行 +1,每次释放的时候进行 -1,当数字为0时,分布式锁被释放,

redis锁如果要支持可重入性,也需要用上面的方式进行支持,不过该逻辑加重了复杂性,一般推荐将需要锁的代码段进行逻辑调整,避免重复获取分布式锁来处理。(当然redisson也支持了可重入锁)

Redlock

上面的方式看起来没有太多的问题了,但是由于redis本身可能也会发生问题,例如在Sentinel集群中,主节点挂掉,从节点变成主节点,但是客户端这时候是不知道的,

如果客户端在刚刚挂掉的主节点上SETNX成功了,但是这把锁还没有同步到从节点中,从节点这时候变成了主节点,这时候新主节点中没有这把锁的信息,

此时另一个客户端来请求这把锁,直接 SETNX 成功,又导致了两个客户端同时在执行相同的代码,又出现了不安全性,

为此业界提供了叫做 Redlock 的解决方案,原理大致是,提供多台redis实例,这些实例之间相互独立,没有主从关系(没有任何关系),同其他分布式算法一样,使用了大多数机制,

加锁时,它会向过半节点发出 set(key, value, nx = True, ex = xxx)指令,只要过半节点设置成功,这把锁就算拿到了,释放锁时向所有节点发出 DEL 指令,

Redlock算法(Redisson已支持)需要考虑出错重试,时钟漂移等等细节问题,同时Redlock需要向多个节点进行读写,性能将要比单例redis下降,

如果业务场景对错误的发生容忍度很低,又可以接受性能稍微有点下降,可以考虑采用Redlock算法。

感谢各位的阅读,以上就是"Redis分布式锁怎么应用"的内容了,经过本文的学习后,相信大家对Redis分布式锁怎么应用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

线程 分布式 应用 代码 节点 问题 程序 就是 成功 情况 指令 数字 时间 结果 要么 进程 相同 两个 同时 字符 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 曲面显示器做软件开发怎么样 数据库用户应用 网络安全作业实施方案 教师线上教学网络技术培训方案 中国人寿软件开发工程师 中广的网络技术有限公司 excel 表格与数据库 艮泰高性能计算服务器可以干什么 网络安全的法律法规是什么 浙江办公系统软件开发哪家好 网络技术前沿与探索 教材 房地产系统数据库设计文档 苏州想学软件开发怎么入手 奇安信网络安全宣传日常 开福区政府网络安全招标 服务器保存不了密码 金山区品牌软件开发厂家价格 找网络技术总监运营总监 数据库如何打开本机图片 软件开发开放数据库 数据库主键外键查询 华为服务器业务出售许昌 工行软件开发外包怎么样 网络安全问题防范方案 idea社区版连接数据库插件 网络安全规划征求意见稿 web服务器安全检测 btav资源服务器 服务器保存不了密码 软件开发的知识产权问题
0