Redis中的分布式锁 - 详解

目录

基于Redis的SetNx命令

实现:

为什么要判断锁是否是本线程加上的(为什么要引入校验id)?

为什么要使用用Lua脚本来完成(为什么要引入Lua)?

问题

基于Redisson

Redisson可重入锁原理

1.获取锁的逻辑

2.释放锁的逻辑

超时续约机制(看门狗机制)

Redisson分布式锁的数据未同步导致线程安全

主从问题:

解决方案:

Redlock 算法的具体过程


基于Redis的SetNx命令

SetNX 如果key已存在,则结果返回0。如果key不存在,则结果返回1。

实现:

1.加锁set unique_key 机器码+线程ID NX EX TTLunique_key一般是业务唯一标识)

  • 加锁成功:执行命令结果返回1
  • 加锁失败:执行命令结果返回0
  • 能搭建互斥且设置了TTL,行通过TTL到期删除key,自动释放锁,防止死锁情况

2.释放锁执行 del 删除 key 的命令

a.先 Get key 拿到 value 判断当前锁是否是本机器本线程加上的

  • 若是,可以正常删除锁
  • 若不是,则不必须处理

为什么要判断锁是否是本线程加上的(为什么要引入校验id)?

是为了防止锁误删的情况

举例: 线程1业务阻塞,锁的TTL到期,Redis key 自动删除,则锁释放,然后线程2获取到了锁。在线程2正常执行时,线程1恢复运行,如果线程1不判断当前锁是否是自己加上的,直接把锁删除了,就出现问题——线程1误删了线程2的锁。

为什么要使用用Lua脚本来完成(为什么要引入Lua)?

因为判断是否是当前线程的锁 + 删除key释放锁 两个处理,这两个操作如果不是原子的就会出现如图片上的问题,使用Lua脚本,使得这两个操作变为原子性的

问题

  • 由于业务执行耗时太长,TTL到期,锁被迫释放,存在多个线程并行的情况
  • SetNX 线程不可重入

  • TTL不好设置,业务到底要执行多长时间,我们不太确定(这个可以引入看门狗解决)

基于Redisson

Redisson 是市面上成熟的分布式锁组件,相对于用 SetNx 命令实现的分布式锁更加强大和完善。

Redisson可重入锁原理

即一个线程可以多次获取锁。利用Hash结构,记录获取锁的线程获取锁的次数

1.获取锁的逻辑

a.判断 key(unique_value一般是业务唯一标识) 是否存在,即判断是否有线程持有锁

  • 假如key不存在,代表没有线程持有锁,则获取锁,即设置一个Hash结构的 (field,value),field是机器码+线程ID,value是 次数 1
  • 如果key存在,代表有线程持有锁,此时判断持有锁的线程是否是当前线程,如果是当前线程,则重入次数+1。
2.释放锁的逻辑

a.重入次数-1,假设重入次数为0,删除key,释放锁。

超时续约机制(看门狗机制)

为了解决TTL不好设置,如果分布式锁的key设置了TTL,又因为业务阻塞原因,导致当前线程的业务未完成,TTL到期了,导致被迫释放锁,此时就会有其他线程抢占锁,导致有线程并行执行,违背了加分布式锁的初心。

当 Redisson 获取锁没有指定锁的TTL时,默认会使用超时续约机制(看门狗WatchDog)机制。

续期规则

  • 默认 TTL 为30 秒,后台线程(定时任务)每隔10 秒检查业务是否结束。
  • 若未达成 → 通过 Lua 脚本重置锁 TTL(续期至 30 秒),保证锁不被释放,等到业务执行完。

Redisson分布式锁的数据未同步导致线程安全

主从问题

  • 主节点宕机时,若从节点未同步 锁 数据 (就是主节点还没来得及把数据给同步到从节点,就挂了,导致加锁失败)→ 新主节点可能允许其他线程重复加锁 →锁失效

解决方案:

  • 此时要求部署多个 Redis 主节点,多主多从架构,向多个主节点都去获取锁
  • MultiLock 联锁方案:要求 所有主节点加锁成功,否则立即失败并释放已获取的锁(要么全部成功要么全部失败)
  • RedLock 红锁方案:要求 半数主节点以上(如 3/5)加锁成功,否则立即失败并释放已获取的锁。
Redlock 算法的具体过程

引⼊⼀组 Redis 节点. 其中每⼀组 Redis 节点都包含⼀个主节点和若⼲从节点. 并且组和组之间存 储的素材都是⼀致的, 相互之间是 "备份" 关系(⽽并⾮是数据集合的⼀部分, 这点有别于 Redis cluster). 加锁的时候, 按照⼀定的顺序, 写多个 master 节点. 在写锁的时候需要设定操作的 "超时时间". ⽐如 50ms. 即假如 setnx 处理超过了 50ms 还没有成功, 就视为加锁失败.

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

"少数服从多数的"就是Redlock 算法的核⼼就是, 加锁操作不能只写给⼀个 Redis 节点, ⽽要写个多个!! 分布式系统中任何⼀个节点都是不可靠的. 最终的加锁成功结论

posted on 2025-12-02 11:40  ljbguanli  阅读(0)  评论(0)    收藏  举报