Redis 分布式锁

为什么需要分布式锁

随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,即单个机器上的锁,无法控制影响其他机器的对数据的行为(数据是共享的,但是锁没有共享)。

分布式锁主流的实现方案:

  • 基于数据库实现分布式锁
  • 基于缓存(Redis等)
  • 基于Zookeeper

分布式锁解决方案都有各自的优缺点

  • 性能:redis最高
  • 可靠性:zookeeper最高

需要满足的四个条件

确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件

  • 互斥性。在任意时刻,只有一个客户端能持有锁。
  • 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  • 专一性,加锁和解锁必须是同一个客户端,解铃还须系铃人,客户端自己不能把别人加的锁给解了。
  • 加锁和解锁必须具有原子性

下面用"公共换衣间"作为例子讲解四个条件。

互斥性

场景解释:

任意时间,换衣间只能有一个人(对应进程)在换衣服。

所以得给换衣间加门锁

Redis 实现:

通过NX(not exist)操作 :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value

不发生死锁

场景解释:

如果换衣间的人,不小心睡着了(对应进程发生异常),那么外面等待的人,永远进不去换衣间,就陷入了死锁!所以,我们得给锁设定最大持有时间

Redis 实现

通过 ex(expire) 操作:对锁设置过期时间SET key value EX seconds

专一性加锁和解锁必须是同一个客户端

场景解释:

如果换衣间的人A睡着了(对应进程A发生异常),一直到锁到期了,下一个人B(对应进程B)进来换衣了,然后A又醒了(进程A恢复了),他径直就打开了门。。。B傻眼了(进程B受到影响)。

所以,我们得使得每个人只能释放自己的锁,不能释放别人的锁!最简单的方式就是,给锁加标识,每个人加锁时,都有一个编号,每次开锁前,得检查是不是自己的编号

Redis 实现:

setnx 获取锁时,设置一个指定的唯一值(例如:uuid;释放前获取这个值,判断是否为自己的锁。

加锁和解锁必须具有原子性

场景解释

之前的加锁流程是,进程 A,Step1: 获取到锁后,Step2: 再设置过期时间,但是如果Step 1之后,进程 A 突然异常,那么锁就没有时间限制了,就会死锁。

之前的解锁流程是,进程 A,step1: 释放前检查uuid编号,一致,step2:再释放锁;但是如果step1 之后,锁刚好过期,然后立马被进程B获取了,那么step2释放的将是B的锁!

上述两个问题,根本原因都是加锁和解锁没有原子性。所以得使加锁和解锁具有原子性。

Redis 实现

加锁:可以用同一条语句,实现同时获取锁和设置过期时间,不分步实现:SET key value NX EX seconds

解锁:可以用lua脚本语言同时实现检查编号和释放锁

// 定义lua 脚本
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";        // 一步实现检查编号和释放锁, KEYS[1] ARGV[1]分别是当前编号和之前获取的编号
// 使用redis执行lua执行
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(script);

TipsLua 是一个小巧的脚本语言Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,Lua并没有提供强大的库,一个完整的Lua解释器不过200k,所以Lua不适合作为开发独立应用程序的语言,而是作为嵌入式脚本语言

LUA脚本是类似redis事务,有一定的原子性不会被其他命令插队,可以完成一些redis事务性的操作。通过lua脚本解决争抢问题,实际上是redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题(库存超卖,用乐观锁会有库存遗留问题,用LUA可以实现类似悲观锁的效果)

image.png

参考:

尚硅谷视频

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容