分布式锁
概述
分布式锁就是分布式场景下的锁,在多线程或多进程并发场景下,使用锁来保证代码块在同一时间内只能由一个线程执行
分布式锁的常用实现方式
set key value nx ex seconds
既有 setnx 特性(nx),也有 ex 表示增加了过期时间
加上 owner
满足 谁申请 谁释放 原则,不能释放别人的锁
在释放锁前:先检查是不是自己的 再释放
场景:服务 A 获取了锁,由于 业务流程较长、网络延迟、GC 卡顿等原因,导致锁过期,而业务还会继续进行。如果这时 服务 B 已经拿到了锁去执行,服务 A 恢复做完业务后,就会释放锁,而 B 却还在继续执行
使用 Lua
检查锁,再释放 不是原子性操作,使用 Lua 整合
可靠性保证
主从容灾:为 Redis 配置从节点,主节点挂了,用从节点顶包。现在也有哨兵模式,不再需要人工介入(主从同步有时延,从节点可能丢失部分数据,分布式锁可能失效)
这里的数据同步时延指的是 Redis 主从复制是异步的,如果客户端在主节点加锁成功,但锁数据还没同步到从节点时主节点宕机,从节点升主后就会丢失这把锁的数据,导致其他客户端再次获取锁,从而造成分布式锁短暂失效
多级部署:RedLock
多个机器,通常是奇数个,达到一半以上同一加锁才算加锁成功
场景:假设有 5个 Redis 主节点
向 5个 Redis 申请加锁
超过一半成功,也就是3个 Redis 返回成功,就算获取到了锁;超过一半失败,需要向每个 Redis 发送解锁命令
向5个 Redis 发送请求,会有时耗,锁剩余持有时间,需要减去请求时间。如果剩余时间已经为0,那么也是获取失败
使用完毕向5个 Redis 发送解锁请求
Redisson
概述
Redisson 是一个基于 Redis 的 Java 分布式并发工具框架,提供高可靠的分布式锁和多种分布式数据结构封装
Redisson 的分布式锁支持可重入,还通过 Watch Dog 机制实现锁自动续期
重试机制
场景:多个线程抢一把锁,没抢到的线程:订阅锁释放的通知(Redis Pub/Sub),等待别的线程释放锁,被通知后,再尝试获取锁
看门狗(Watch Dog)机制
场景:如果你设置锁过期时间 10 秒,但业务执行 30 秒: 锁过期,别人进来 两个线程同时执行 = 数据错乱
看门狗 = 自动续命,只要线程还活着,就帮锁自动延期,像这样:每隔 10 秒,给锁续期 30 秒,一直续,直到线程结束
可重入
同一个线程第一次加锁,成功,第二次加锁,也成功(还是同一个线程),释放锁要释放两次才真的解锁
Redisson 可重入锁底层基于 Redis Hash 结构实现,使用线程唯一标识作为 field,重入次数作为 value。加锁时如果是同一线程则递增计数,释放锁时递减计数,只有计数归零才删除锁 Key。整个过程通过 Lua 脚本保证原子性,从而实现分布式可重入锁