Redisson 分布式锁实现:可重入与看门狗

引言

在分布式架构中,多台服务器共享同一资源时,传统的 JVM 锁已无法保障数据一致性,分布式锁由此成为关键。Redisson 基于 Redis 实现的分布式锁,不仅支持可重入、自动续期,还通过发布订阅机制高效处理锁竞争。本文从加锁、锁续命、锁释放三个环节,深入解析 Redisson 的核心设计,包括 Lua 脚本保证原子性、Watch Dog 看门狗的定时续期机制,以及如何灵活控制锁的失效策略。

Redisson分布式锁实现

分布式锁是为了解决分布式架构中多台服务器共享资源的并发问题,单体时代可以使用JVM锁解决并发问题,但分布式架构中,同时存在多台服务器执行同样的逻辑,也就是在多套JVM环境下执行同样的逻辑,此时JVM锁无法生效,所以需要分布式锁。

加锁过程

还未加锁

  1. 先判断是否存在key为KEYS[1]的键值对(==0表示不存在),如果不存在表示未加锁。

  2. 通过hset(Hash结构)设置<锁名称, <UUID + 线程ID, 1>>,KEYS[1] = 锁名称,ARGV[2] = UUID + 线程ID。

  3. 通过pexpire设置key的过期时间,默认30s。

已经加锁

  1. 通过hexists(Hash结构)判读前线程是否加锁成功,如果当前线程加锁成功走2。

  2. 给当前线程的value+1。

  3. 在次通过pexpire设置key的过期时间,默认30s。

加锁失败

  1. 通过ttl返回剩余过期时间,方便后续线程重试去竞争锁,如果加锁成功则返回null。

  2. 加锁失败后会订阅频道(redisson_lock__channel + lockName)返回一个Future用于获得锁释放通知,并通过Semaphore.tryAcquire(ttl, TimeUnit.MILLISECONDS)在ttl时间内尝试获取一个信号量许可,获取到信号量许可后再次进行锁竞争,直至成功。

锁续命过程

使用锁续命而不是不限时的锁,是为了防止用户线程崩溃,导致锁一直未释放。所以每隔一段时间进行锁的续命,而不是设置永久锁,这样即便用户线程崩溃,也只是30s,无法访问。

  1. 锁续命需要判断用户是否设置过期时间,如果设置了过期时间,不会进行锁续命。

  2. 通过定时任务每30/3秒,找到当前线程对应的锁,如果存在重新设置过期时间为30秒。

锁释放过程

  1. 判断线程id(小key)是否存在,如果不存在,则返回null;如果存在,则可重入次数-1。

  2. 再判断可重入次数是否 > 0,如果 > 0,则不能释放锁,并重新设置锁过期时间。

  3. 如果 <= 0,则删除redis的大key,往(redisson_lock__channel + lockName)频道发送message,发送UNLOCK_MESSAGE。

Watch Dog(看门狗)

看门狗如何实现锁续期的?

第一次进入的时候,这里放进去的就是一个全新的ExpirationEntry类,并进行续约操作。续约操作其实就是创建一个延迟任务,默认每10s执行一次,延迟任务由HashedWheelTimer实现,核心是时间轮算法

如何修改看门狗续期时间?

配置lockWatchdogTimeout参数,可以调整看门狗续期频率和续期时间,默认lockWatchdogTimeout/3秒自动需求。

复制代码
Config config = new Config();
config.setLockWatchdogTimeout(60000); // 设置为 60 秒

如何设置看门狗不会续期?

指定leaseTime参数,这表示锁的有效期。在这个时间之后,如果没有主动释放,锁将自动失效并释放资源。

复制代码
RLocklock= redissonClient.getLock("myLock"); 
// 试图加锁,锁的过期时间设置为10秒钟 
lock.lock(10, TimeUnit.SECONDS);

情况下,Redisson的看门狗机制会停止续期?

  • 第一种情况:手工调用停止续期方法即cancelExpirationRenewal(),看门狗机制会停止续期。

  • 第二种情况:调用unlock()释放分布式锁后,看门狗机制也会停止续期。

  • 第三种情况:如果尝试续期的过程中,当前线程被中断,看门狗机制也会停止续期。

  • 第四种情况:应用程序宕机或者进程被kill掉,看门狗机制也会停止续期。


感谢您的阅读!如果文章中有任何问题或不足之处,欢迎及时指出,您的反馈将帮助我不断改进与完善。期待与您共同探讨技术,共同进步!

相关推荐
uElY ITER2 小时前
基于Spring Boot 3 + Spring Security6 + JWT + Redis实现登录、token身份认证
spring boot·redis·spring
java干货4 小时前
如果光缆被挖断导致 Redis 出现两个 Master,怎么防止数据丢失?
数据库·redis·缓存
郝开4 小时前
Docker Compose 本地环境搭建:redis
redis·docker·容器
人道领域5 小时前
【黑马点评日记】高并发秒杀:库存超卖与锁机制解析
java·开发语言·redis·spring·intellij-idea
qq_283720056 小时前
Python3 模块精讲:Redis 第三方库从入门到精通全攻略
redis·缓存
tonydf7 小时前
一次由组件并发引发的类“缓存击穿”问题排查与修复
redis·后端·架构
爱喝雪碧的可乐7 小时前
【Redis 毁灭计划】7 大高危操作打崩线上服务!从缓存雪崩到数据库宕机,90% 程序员都踩过的坑
开发语言·网络·redis·php
彭于晏Yan8 小时前
Spring Boot 整合 WebSocket + Redis 实现离线消息(三)
spring boot·redis·websocket
fengxin_rou8 小时前
黑马点评实战篇|第七篇:Redis消息队列
数据库·redis·缓存
千月落9 小时前
Redis Cluster 集群部署
数据库·redis·缓存