Redis分布式锁从入门到精通:从SETNX到Redisson看门狗机制
Redis分布式锁从入门到精通从SETNX到Redisson看门狗机制引言1. 分布式锁的核心要求2. 基于Redis的简易分布式锁实现2.1 第一阶段SETNX EXPIRE有问题2.2 第二阶段SET原子操作正确基础版2.3 第三阶段安全解锁Lua脚本2.4 完整基础代码示例Java版2.5 基础版流程图3. 基础版存在的问题4. 工业级方案Redisson分布式锁4.1 Redisson快速入门4.2 核心特性5. Redisson源码深度剖析5.1 加锁核心Lua脚本5.2 加锁流程图5.3 看门狗机制自动续期5.4 可重入实现原理6. 分布式锁的扩展形态6.1 读写锁ReadWriteLock6.2 公平锁FairLock6.3 红锁RedLock7. 最佳实践与避坑指南7.1 合理设置过期时间7.2 务必在finally中释放锁7.3 监控与告警8. 总结对比核心观点The Begin点点关注收藏不迷路引言在分布式系统中多个服务节点同时操作共享资源时传统的单机锁如synchronized、ReentrantLock就失效了。如何保证同一时刻只有一个节点能执行关键代码分布式锁就是解决方案。Redis凭借其高性能和原子操作成为实现分布式锁的首选工具。本文将深入剖析Redis分布式锁的实现原理、常见坑点以及工业级解决方案Redisson的源码级解析。1. 分布式锁的核心要求在设计分布式锁时必须满足以下四个条件要求说明互斥性同一时刻只有一个客户端能持有锁死锁预防持有锁的客户端崩溃或网络异常锁能自动释放容错性大多数Redis节点正常运行时客户端仍可加解锁解铃还须系铃人加锁和解锁必须是同一个客户端不能释放别人的锁2. 基于Redis的简易分布式锁实现2.1 第一阶段SETNX EXPIRE有问题最原始的想法用SETNX加锁再用EXPIRE设过期时间。# 1. 加锁SETNX lock_key1# 2. 设置过期时间防止死锁EXPIRE lock_key30问题所在SETNX和EXPIRE是两个命令非原子性。如果SETNX成功后客户端崩溃EXPIRE没执行就导致死锁2.2 第二阶段SET原子操作正确基础版Redis 2.6.12提供了SET命令的扩展参数解决了原子性问题SET lock_key unique_value NX PX30000参数说明NX只有key不存在时才设置实现互斥PX 30000设置过期时间30秒防止死锁unique_value客户端唯一ID如UUID用于安全释放锁2.3 第三阶段安全解锁Lua脚本为什么释放锁要用Lua脚本因为要确保当前客户端只能释放自己加的锁不能误删别人的锁。-- 解锁Lua脚本ifredis.call(get,KEYS[1])ARGV[1]thenreturnredis.call(del,KEYS[1])elsereturn0end2.4 完整基础代码示例Java版publicclassRedisDistributedLock{privateJedisjedis;privateStringlockKey;privateStringuniqueValue;privateintexpireTime;// 毫秒publicbooleantryLock(){// SET key value NX PX expireTimeStringresultjedis.set(lockKey,uniqueValue,NX,PX,expireTime);returnOK.equals(result);}publicbooleanunlock(){StringluaScriptif redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;Objectresultjedis.eval(luaScript,Collections.singletonList(lockKey),Collections.singletonList(uniqueValue));returnLong.valueOf(1).equals(result);}}2.5 基础版流程图RedisClientBClientARedisClientBClientA业务执行完成SET lock UUID_A NX PX 30000OK (加锁成功)SET lock UUID_B NX PX 30000(nil) 加锁失败执行业务逻辑...EVAL 解锁脚本 (UUID_A)检查valueUUID_Adel成功SET lock UUID_B NX PX 30000OK (加锁成功)3. 基础版存在的问题上述实现虽然正确但在生产环境中仍有几个痛点锁超时释放业务执行时间超过过期时间锁自动释放导致并发问题不可重入同一线程无法多次获取同一把锁不支持等待获取不到锁直接返回失败没有阻塞等待机制无续期机制无法在业务执行过程中延长锁的有效期4. 工业级方案Redisson分布式锁Redisson是Redis官方推荐的Java分布式锁实现完美解决了上述所有问题。4.1 Redisson快速入门dependencygroupIdorg.redisson/groupIdartifactIdredisson/artifactIdversion3.20.0/version/dependencyConfigurationpublicclassRedissonConfig{BeanpublicRedissonClientredissonClient(){ConfigconfignewConfig();config.useSingleServer().setAddress(redis://127.0.0.1:6379).setPassword(123456).setConnectionPoolSize(10);returnRedisson.create(config);}}ServicepublicclassOrderService{AutowiredprivateRedissonClientredissonClient;publicvoidcreateOrder(LongorderId){// 1. 获取分布式锁RLocklockredissonClient.getLock(order:orderId);try{// 2. 加锁支持自动续期lock.lock(30,TimeUnit.SECONDS);// 3. 执行业务逻辑doBusiness();}finally{// 4. 释放锁lock.unlock();}}}4.2 核心特性特性说明可重入同一线程可多次获取同一把锁内部计数器维护自动续期看门狗机制业务未完成自动延长过期时间阻塞等待支持tryLock带超时时间的等待公平锁支持FIFO顺序获取锁读写锁读读共享、读写互斥、写写互斥5. Redisson源码深度剖析5.1 加锁核心Lua脚本Redisson的加锁逻辑通过Lua脚本实现原子性源码如下TRFutureTtryLockInnerAsync(longleaseTime,TimeUnitunit,longthreadId,RedisStrictCommandTcommand){returncommandExecutor.evalWriteAsync(getName(),LongCodec.INSTANCE,command,// 1. 判断锁是否存在if (redis.call(exists, KEYS[1]) 0) then redis.call(hincrby, KEYS[1], ARGV[2], 1); redis.call(pexpire, KEYS[1], ARGV[1]); return nil; end; // 2. 判断是否是当前线程持有if (redis.call(hexists, KEYS[1], ARGV[2]) 1) then redis.call(hincrby, KEYS[1], ARGV[2], 1); redis.call(pexpire, KEYS[1], ARGV[1]); return nil; end; // 3. 其他线程持有返回剩余过期时间return redis.call(pttl, KEYS[1]);,Collections.singletonList(getName()),unit.toMillis(leaseTime),getLockName(threadId));}数据结构说明Redisson使用Hash结构存储锁信息key: 锁名称如order:123field: 线程标识如UUID:threadIdvalue: 重入计数5.2 加锁流程图否是是否收到信号调用lock方法执行Lua加锁脚本锁是否存在?创建Hash,重入计数1,设置过期时间是否是当前线程?重入计数1,重置过期时间返回锁剩余过期时间加锁成功订阅锁释放Channel等待锁释放信号启动看门狗定期续期5.3 看门狗机制自动续期看门狗是Redisson最核心的特性解决了业务执行超时导致锁自动释放的问题。privatevoidscheduleExpirationRenewal(longthreadId){ExpirationEntryentrynewExpirationEntry();EXPIRATION_RENEWAL_MAP.put(getEntryName(),entry);// 定时任务每10秒执行一次TimeouttaskcommandExecutor.getConnectionManager().newTimeout(newTimerTask(){Overridepublicvoidrun(Timeouttimeout)throwsException{// 续期Lua脚本重置锁过期时间为30秒RFutureBooleanfuturerenewExpirationAsync(threadId);future.onComplete((res,e)-{if(res){// 续期成功递归调用继续续期scheduleExpirationRenewal(threadId);}});}},internalLockLeaseTime/3,TimeUnit.MILLISECONDS);// 默认30秒/310秒执行一次entry.setTimeout(task);}看门狗工作流程客户端加锁成功默认过期时间30秒启动后台线程每10秒检查一次如果锁仍被当前线程持有执行续期Lua脚本重置过期时间为30秒业务执行完毕主动释放锁取消看门狗如果客户端崩溃看门狗停止续期锁30秒后自动释放5.4 可重入实现原理通过Hash结构的计数器实现可重入# 第一次加锁HSETorder:123clientA:thread11PEXPIREorder:12330000# 同一线程再次加锁HINCRBYorder:123clientA:thread11# 计数变为2PEXPIREorder:12330000# 重置过期时间# 释放锁HINCRBYorder:123clientA:thread1-1# 计数减1# 计数0保留锁# 计数0删除key6. 分布式锁的扩展形态Redisson还提供了多种高级锁类型6.1 读写锁ReadWriteLock适用于读多写少的场景提升并发性能。RReadWriteLockrwLockredissonClient.getReadWriteLock(data-lock);RLockreadLockrwLock.readLock();// 读锁RLockwriteLockrwLock.writeLock();// 写锁// 读锁可被多个线程同时持有readLock.lock();// 写锁独占writeLock.lock();6.2 公平锁FairLock保证先等待的线程先获得锁。RLockfairLockredissonClient.getFairLock(fair-lock);fairLock.lock();// 按请求顺序分配6.3 红锁RedLock多Redis节点部署时的高可用方案需要大多数节点同意才能加锁。7. 最佳实践与避坑指南7.1 合理设置过期时间// 错误过期时间太短业务可能未完成lock.lock(5,TimeUnit.SECONDS);// 正确使用默认30秒配合看门狗自动续期lock.lock();// 或者根据业务评估设置足够长时间lock.lock(60,TimeUnit.SECONDS);7.2 务必在finally中释放锁RLocklockredissonClient.getLock(key);lock.lock();try{// 业务逻辑}finally{// 确保一定释放if(lock.isLocked()lock.isHeldByCurrentThread()){lock.unlock();}}7.3 监控与告警ComponentpublicclassLockMonitor{privatestaticfinalMeterRegistryregistrynewSimpleMeterRegistry();// 监控锁等待时间privateTimerlockWaitTimerTimer.builder(lock.wait.time).register(registry);// 监控锁持有时间privateTimerlockHoldTimerTimer.builder(lock.hold.time).register(registry);publicTTexecuteWithMonitor(StringlockKey,SupplierTsupplier){RLocklockredissonClient.getLock(lockKey);longstartWaitSystem.currentTimeMillis();lock.lock();longwaitTimeSystem.currentTimeMillis()-startWait;lockWaitTimer.record(waitTime,TimeUnit.MILLISECONDS);longstartHoldSystem.currentTimeMillis();try{returnsupplier.get();}finally{lock.unlock();longholdTimeSystem.currentTimeMillis()-startHold;lockHoldTimer.record(holdTime,TimeUnit.MILLISECONDS);// 告警检查if(holdTime10000){// 持有超过10秒alertService.sendAlert(锁持有时间过长: lockKey);}}}}8. 总结对比方案优点缺点适用场景SETNX基础版实现简单无续期、不可重入学习测试手动Lua脚本原子操作功能单一简单场景Redisson功能完善、自动续期、可重入引入依赖生产环境首选核心观点原子性是基础加解锁必须用Lua或原子命令唯一标识是关键用UUID标识锁持有者防止误删看门狗是保障自动续期解决业务超时问题选型要慎重生产环境直接用Redisson不要重复造轮子The End点点关注收藏不迷路

相关新闻

改稿速度拉满!专科生专属降AI神器 —— 千笔AI

改稿速度拉满!专科生专属降AI神器 —— 千笔AI

在AI技术迅速渗透学术写作的当下,越来越多的专科生开始借助AI工具提升论文撰写效率。然而,随着查重系统对AI生成内容的识别能力不断提升,如何有效降低AI率和重复率,成为许多学生面临的棘手问题。面对市场上琳琅满目的降AI工具&…

2026/7/3 14:24:55 阅读更多 →
Vue3基于python的小区体育运动中心预约管理系统的设计与实现(编号:11900325)

Vue3基于python的小区体育运动中心预约管理系统的设计与实现(编号:11900325)

目录技术背景与需求分析系统架构设计核心功能模块关键技术实现数据库设计部署与优化测试与安全开发技术路线源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!技术背景与需求分析 Vue3与Python技术栈的优势:前端响应式框架Vue3提…

2026/5/17 6:17:10 阅读更多 →
知识库智能客服系统架构设计与实现:从技术选型到生产环境避坑指南

知识库智能客服系统架构设计与实现:从技术选型到生产环境避坑指南

最近在做一个知识库智能客服项目,从零开始搭建,踩了不少坑,也积累了一些经验。今天就来聊聊这类系统的架构设计与实现,重点分享从技术选型到生产环境部署的完整思路和避坑点。希望能给正在做类似项目的朋友一些参考。 1. 背景与痛…

2026/7/3 2:58:19 阅读更多 →

最新新闻

Subliminal进阶:模拟复杂用户交互和系统对话框的完整指南

Subliminal进阶:模拟复杂用户交互和系统对话框的完整指南

Subliminal进阶:模拟复杂用户交互和系统对话框的完整指南 【免费下载链接】Subliminal An understated approach to iOS integration testing. 项目地址: https://gitcode.com/gh_mirrors/subl/Subliminal Subliminal是一个强大的iOS集成测试框架&#xff0c…

2026/7/5 17:05:07 阅读更多 →
Android分布式架构深度解析:基于空间架构模式的终极实践指南

Android分布式架构深度解析:基于空间架构模式的终极实践指南

Android分布式架构深度解析:基于空间架构模式的终极实践指南 【免费下载链接】android-tech-frontier 【停止维护】一个定期翻译国外Android优质的技术、开源库、软件架构设计、测试等文章的开源项目 项目地址: https://gitcode.com/gh_mirrors/an/android-tech-f…

2026/7/5 17:05:07 阅读更多 →
一套方案跑通三大平台:YOLO全场景部署实战指南,附一键环境配置脚本

一套方案跑通三大平台:YOLO全场景部署实战指南,附一键环境配置脚本

做工业视觉落地的同行应该都有同感:训模型只是第一步,部署才是磨死人的开始。同一份YOLO权重,既要跑Windows产线上位机,又要部署Linux后台服务器,还要塞进Jetson边缘盒子,每个平台环境依赖不一样、推理引擎…

2026/7/5 17:03:07 阅读更多 →
MarkItDown:如何用Python统一处理数十种文档格式

MarkItDown:如何用Python统一处理数十种文档格式

MarkItDown:如何用Python统一处理数十种文档格式 【免费下载链接】markitdown Python tool for converting files and office documents to Markdown. 项目地址: https://gitcode.com/GitHub_Trending/ma/markitdown 想象一下这样的场景:你的桌面…

2026/7/5 17:03:07 阅读更多 →
NVC多平台部署指南:Linux、macOS和Windows下的安装与配置

NVC多平台部署指南:Linux、macOS和Windows下的安装与配置

NVC多平台部署指南:Linux、macOS和Windows下的安装与配置 【免费下载链接】nvc VHDL compiler and simulator 项目地址: https://gitcode.com/gh_mirrors/nv/nvc NVC是一款开源的VHDL编译器和模拟器,支持VHDL-2008标准并具有出色的模拟性能。本指…

2026/7/5 17:03:07 阅读更多 →
3步掌握MinerU:构建智能文档解析系统的实战指南

3步掌握MinerU:构建智能文档解析系统的实战指南

3步掌握MinerU:构建智能文档解析系统的实战指南 【免费下载链接】MinerU Transforms complex documents like PDFs and Office docs into LLM-ready markdown/JSON for your Agentic workflows. 项目地址: https://gitcode.com/GitHub_Trending/mi/MinerU Mi…

2026/7/5 17:03:07 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻