Redis——分布式锁

分布式锁

引言

其实这个章节,也都是从架构入手,了解其具体的架构思想,并根据实际情况去用相应的代码

所以本篇着重在于带大家理解架构,代码的话其实有Java的基础都不是很难的~~

为什么需要分布式锁

问 :已经有 synchronized 了,为什么还要搞 Redis 分布式锁?

答:

"synchronized 和 ReentrantLock 是 JVM 级别的锁,只能锁住当前这一个进程。但在分布式系统(微服务)中,我们通常有多台服务器(Tomcat)同时运行。比如'秒杀'场景,A 服务器和 B 服务器上的代码都能拿到库存,这就导致超卖。
分布式锁的核心目的,就是跨 JVM 实现互斥,让在同一时刻,全宇宙(集群)只有一个人能操作资源。"

加锁的三个核心原则

原子性(要么都有,要么都无)

  • 问 :先 set 再 expire 会有原子性问题吗?
  • 回 :必须强调使用 SET key value NX EX 命令(或者 Java 里的 setIfAbsent 配合 TimeUnit)。这两步必须是原子的,否则在设置值之后、设置过期时间之前,如果宕机了,就会产生死锁。

防死锁(过期时间)

  • 问:如果线程获取锁后,业务还没执行完服务器就挂了,怎么办?
  • 回 :给锁设置一个自动过期时间(expire)。如果持有锁的客户端宕机,Redis 会自动删除 Key,让锁自动释放,防止死锁。

防误删(唯一标识)

  • 问:A 拿到锁,过期了;B 拿到了锁;A 醒了把 B 的锁删了,怎么办?
  • 回 :这是个大坑。不能直接 del。必须在 Value 里存一个唯一标识(比如 UUID)。删除前要判断:只有当 Key 对应的 Value 是我自己的 UUID 时,我才允许删除。否则就不动。

关于"防误删"的进阶细节(原子性 + Lua)

问:要先判断再删除,那判断和删除不是原子性的怎么办?

答:

"这是一个非常关键的点。如果在 GET 判断之后,DEL 之前,锁过期了,这时候另一个客户端 C 又抢到了锁,那么原来的客户端再去 DEL,就会误删 C 的锁。
解决方案 :必须使用 Lua 脚本 。把'判断是否为自己的锁'和'删除锁'这两个操作封装成一个 Lua 脚本,通过 EVAL 命令发给 Redis 执行。因为 Redis 是单线程的,Lua 脚本在执行期间不会被中断,从而保证了原子性。"

Redis 集群下的脑裂问题

问:你的方案在单机 Redis 没问题,如果 Redis 是主从架构(Master-Slave)呢?

答:

"这里确实存在一个风险,通常叫'脑裂'或者'锁失效'。
场景 :客户端 A 在 Master 上拿到了锁。此时 Master 还没来得及把数据同步给 Slave,Master 挂了。Slave 升级为新的 Master。这时候客户端 B 发起请求,也能拿到锁。
结果 :A 和 B 同时拿到了锁,锁失效了。
解决方案 :业界通常使用 Redlock 算法 (需要向大多数节点申请锁),或者更推荐使用 Zookeeper(基于 ZAB 协议,强一致性)。不过在实际业务中,为了简单,我们通常依赖 Redis 的持久化和高可用机制,容忍极小概率的锁失效。"

相关推荐
余槐i4 分钟前
WAL 下写并发仍是 1:SQLite 单写者模型实测与绕开方案
数据库·python·性能优化·sqlite·wal
hweiyu008 小时前
Redis命令:HSTRLEN
redis·缓存
阳光九叶草LXGZXJ8 小时前
达梦数据库-报错-15-列【XXX】长度超出定义
linux·运维·数据库·sql·学习
字节渡客9 小时前
Redis键明明过期了,业务还在读到旧数据
数据库·redis·spring
前端兰博11 小时前
05-Redis
redis·后端
OnlineProxy11 小时前
亚马逊多账号运营:如何在规避“关联封号”风险的同时实现电商规模化扩张
服务器·数据库·redis
辻弋20112 小时前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
可乐鸡翅yeah_13 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
石头麻辣鱼14 小时前
Bamboo 调度系统 OceanBase 适配实战:存储过程迁移踩过的三个大坑
数据库
龙亘川14 小时前
数智驱动民政升级 精准守护民生保障
大数据·数据库·人工智能