1. 为什么需要分布式锁在分布式系统中多个服务实例同时访问共享资源时会出现并发问题。比如电商系统中的库存扣减、秒杀活动中的商品抢购都需要保证同一时间只有一个客户端能够执行关键操作。这就是分布式锁要解决的核心问题。单机环境下我们可以用Java的synchronized或者ReentrantLock但在分布式系统中这些本地锁机制就失效了。因为你的应用可能部署在多台服务器上每台服务器都有自己的JVM进程本地锁只能控制当前进程内的线程同步。分布式锁的本质是在分布式系统中找到一个所有节点都能访问的仲裁者通过这个仲裁者来协调各个节点的互斥访问。Redis之所以常被用作分布式锁的实现方案主要基于以下几个特性高性能加锁解锁操作通常在毫秒级完成原子性Redis的单线程模型保证了命令执行的原子性持久化虽然不必须但持久化可以防止锁丢失丰富的数据结构String、Hash等结构都可用于实现锁2. Redis分布式锁的三种实现方式2.1 SETNX EXPIRE方案这是最基础的实现方式主要依赖Redis的两个命令SETNX lock_key unique_value # 尝试获取锁 EXPIRE lock_key 10 # 设置过期时间这种方式的典型问题在于SETNX和EXPIRE是两个独立操作不是原子的。如果在SETNX成功后客户端崩溃没有执行EXPIRE就会导致死锁。我在实际项目中就遇到过这样的生产事故一个服务重启后之前获取的锁没有释放又没有设置过期时间导致整个系统卡死。最后只能手动登录Redis删除这个key。2.2 SET命令扩展方案Redis 2.6.12之后SET命令支持了NX和EX选项可以原子性地完成加锁和设置过期时间SET lock_key unique_value NX EX 10这个命令的意思是只有当lock_key不存在(NX)时才设置并且设置10秒的过期时间(EX)。这样就完美解决了2.1方案中的原子性问题。重要提示unique_value必须是全局唯一的通常可以使用UUID或者客户端ID时间戳。这是为了确保只有锁的持有者才能释放锁防止误删其他客户端的锁。2.3 Redisson框架方案对于Java开发者来说Redisson提供了更高级的分布式锁实现。它解决了以下几个关键问题锁的自动续期看门狗机制可重入锁支持公平锁支持锁等待机制使用示例RLock lock redisson.getLock(myLock); try { lock.lock(); // 业务代码 } finally { lock.unlock(); }Redisson的实现原理比较复杂它底层使用Lua脚本保证原子性通过发布订阅机制实现锁等待通过定时任务实现锁续期。我们会在第4章详细分析。3. Redis分布式锁的八大避坑点3.1 锁过期时间设置不当这是最常见的坑。时间设太短业务没执行完锁就释放了设太长客户端崩溃后其他客户端要等待很久。经验值常规业务10-30秒耗时操作按实际耗时×2设置不确定时使用Redisson的看门狗机制自动续期3.2 非原子性操作如2.1节所述分开执行SETNX和EXPIRE会导致死锁。必须使用原子命令或者Lua脚本。3.3 误删其他客户端的锁错误的解锁代码if(redis.get(lock_key) ! null) { redis.del(lock_key); }正确的解锁代码应该验证unique_valueif redis.call(get,KEYS[1]) ARGV[1] then return redis.call(del,KEYS[1]) else return 0 end3.4 锁不可重入简单的Redis锁实现不支持重入会导致死锁。解决方案使用Redisson的可重入锁自己实现计数逻辑维护一个计数器3.5 锁等待处理不当直接循环获取锁会导致Redis压力过大。正确做法设置合理的等待超时时间使用随机退避算法如指数退避考虑使用Redisson的订阅机制3.6 主从切换导致锁失效Redis主从同步是异步的主节点崩溃时可能导致锁丢失。解决方案使用RedLock算法有争议使用Redis集群模式接受小概率的锁失效做好幂等处理3.7 业务执行时间超过锁过期时间这会导致多个客户端同时持有锁。解决方案合理评估业务耗时使用Redisson的看门狗自动续期将大任务拆分为小任务3.8 未考虑网络分区在发生网络分区时可能出现多个客户端同时认为自己持有锁。CAP理论告诉我们这种情况下需要在一致性和可用性之间权衡。4. Redisson分布式锁实现原理深度解析Redisson的分布式锁实现是生产级方案中最完善的我们来深入分析它的核心机制。4.1 加锁流程客户端A执行加锁命令if (redis.call(exists, KEYS[1]) 0) then redis.call(hset, KEYS[1], ARGV[2], 1) redis.call(pexpire, KEYS[1], ARGV[1]) return nil end这个Lua脚本会检查锁是否存在不存在则设置Hash结构field是客户端IDvalue是重入次数。如果锁已存在但是是当前客户端持有的则增加重入计数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如果锁被其他客户端持有则返回锁的剩余生存时间。4.2 看门狗机制Redisson会启动一个定时任务默认每10秒检查一次锁如果客户端还持有锁就延长锁的生存时间。这样可以避免业务执行时间超过锁过期时间的问题。4.3 解锁流程解锁时会减少重入计数当计数为0时删除keyif (redis.call(hexists, KEYS[1], ARGV[3]) 0) then return nil end local counter redis.call(hincrby, KEYS[1], ARGV[3], -1) if (counter 0) then redis.call(pexpire, KEYS[1], ARGV[2]) return 0 else redis.call(del, KEYS[1]) redis.call(publish, KEYS[2], ARGV[1]) return 1 end4.4 锁等待机制当锁被占用时Redisson会通过Redis的发布订阅功能监听锁释放事件而不是不断轮询这大大减少了Redis的压力。5. 面试中常见问题及回答技巧5.1 Redis分布式锁的实现原理是什么回答要点基于SETNX或SET命令的原子性唯一value防止误删过期时间防止死锁可选的Redisson高级特性5.2 Redis分布式锁有什么缺点回答要点主从切换可能导致锁失效锁过期时间难以精确设置网络分区时的脑裂问题性能与一致性的权衡5.3 如何解决Redis主从切换导致的锁失效问题回答要点RedLock算法但存在争议接受小概率失效做好幂等使用Zookeeper等强一致性系统但性能较低5.4 除了Redis还有哪些分布式锁实现方案回答要点Zookeeper的顺序节点和watch机制etcd的租约和事务数据库的唯一索引对比各自的优缺点5.5 在项目中如何选择合适的分布式锁方案回答框架评估业务对一致性的要求评估系统的性能需求考虑团队的技术栈考虑运维复杂度我在实际项目中通常会这样选择高一致性场景Zookeeper高性能场景Redis 幂等处理Java技术栈优先考虑Redisson
企业数字化 ERP 产品动态
相关推荐
Java基础入门课后习题答案精讲:核心概念与常见误区解析 简介:这份文档面向Java初学者与高校学生,针对《Java基础入门》教材课后习题提供系统参考答案,帮助读者在学完每章后及时核对思路、巩固语法与概念。内容覆盖Java开发入门、语言基础、程序设计与面向对象编程四大板块,包含填空、判… · 2026/11/3 19:57:35
十亿级用户名校验的架构设计与优化实践 1. 十亿级用户名的技术挑战当Instagram用户量突破十亿大关时,"用户名已被占用"这个看似简单的提示背后,隐藏着极其复杂的工程挑战。每天有数百万用户同时尝试注册、修改用户名,系统需要在毫秒级响应时间内完成全球唯一性校验&#… · 2026/11/3 19:57:35
缴费基数上下限调整实操:口径判定、系统配置与补差核算 通知落到工资表上的那天,往往是HR和财务一年里最忙的几天。群里最先冒出来的问题永远不是"职工基本养老保险缴费基数上下限"这几个字怎么念,而是"我这个月怎么少了两百块"。缴费基数上下限这份年度通知,看着只有几个数字… · 2026/11/3 19:57:35
Unity3D图片花边与马赛克问题全解析:从纹理设置到渲染管线 1. 一张图跑起来就"碎"了:先搞清楚花边和马赛克到底是不是一回事Unity3D项目在编辑器里预览得好好的,一点运行,图片边缘就出现锯齿状的花边,或者整张图糊成一块一块的马赛克,这个现象我见过太多次了。很多人… · 2026/11/3 22:17:08
Buzz实战:Whisper语音转文字模型选型与调优 录音转文字这件事,我从人工听写一路折腾到各种云服务,最后固定在 Buzz 这个开源桌面工具上。最近几次给播客做字幕、给访谈做纪要,基本都是在它上面一键批量完成的。这篇文章不聊空泛的“工具推荐”,就务实记录我把 Buzz 用顺手的… · 2026/11/3 22:17:08
西工大美育真题解码:从考试卷到审美能力训练说明书 简介:本资源为西北工业大学《大学美育》课程2021年春季学期完整真题试卷,面向高校本科生、美育课程学习者及人文素养提升需求者,聚焦审美理论理解、美学概念辨析与艺术实践反思能力训练。试卷涵盖判断题、多选题、案例分析、诗歌鉴赏与论述五… · 2026/11/3 22:17:08
回形针为何百年不变?设计原理、材料工艺与隐藏用法解析 这是我桌面上最不起眼的一个小东西——一枚直径不到一厘米的钢圈,却实打实地服务了人类一百多年。每次我整理项目资料,把一沓A4纸用回形针(paperclip)别在一起的时候,总忍不住想:为什么是它?为什… · 2026/11/3 22:17:08
AI代理约束工程:重塑人机协作的软件开发新范式 1. AI Agent Harness Engineering的本质与组织价值AI Agent Harness Engineering(AI代理约束工程)正在重塑人机协作的底层逻辑。这个概念的核心理念可以概括为:AI代理模型(Model)约束系统(Harness)。就像赛车手需要安全带和防滚架的保护一样&… · 2026/11/3 22:17:08
GPT your dot:用大模型重构开发者配置管理 1. 这句“GPT your dot!”到底在喊什么?你刷到过这句话吗?——“GPT your dot!都给我去用!!”不是拼写错误,不是中英混搭的尴尬现场,更不是某个小众编程语言的新语法。它是一句带着强… · 2026/11/3 22:16:08
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46