RedLock:Redis 分布式锁的高可用方案
RedLockRedis 分布式锁的高可用方案一、RedLock 要解决什么问题单 Redis 节点锁的缺陷时刻T1: 客户端A → 在 Master 加锁成功 时刻T2: Master 宕机锁数据还没同步到 Slave 时刻T3: Slave 提升为新 Master没有锁信息 时刻T4: 客户端B → 在新 Master 加锁成功 时刻T5: 客户端A 和 B 同时持有锁 → 互斥失效即使使用 Redis Sentinel 或 Cluster也存在这个问题——Redis 主从复制是异步的切换瞬间可能丢数据。RedLock 的思路不依赖单个 Redis 节点而是同时在多个独立 Redis 节点上加锁多数成功才算加锁成功┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Redis-1 │ │ Redis-2 │ │ Redis-3 │ │ Redis-4 │ │ Redis-5 │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ ✅ ✅ ❌ ✅ ❌ 成功3个 ≥ 多数(3/5) → 加锁成功即使 1-2 个节点宕机或网络不通锁依然有效。注博客https://blog.csdn.net/badao_liumang_qizhi二、RedLock 算法流程加锁步骤1. 记录开始时间 T1 2. 依次在 N 个独立 Redis 节点上执行加锁 SET lock_key random_value NX PX ttl - 每个节点设置一个较短的超时如 5-50ms - 某个节点超时或失败则立即跳过继续下一个 3. 记录结束时间 T2 4. 计算加锁耗时elapsed T2 - T1 5. 判断是否加锁成功 - 成功节点数 ≥ N/2 1多数 - 且 elapsed ttl锁还没过期 6. 如果成功 - 锁的实际有效时间 ttl - elapsed 7. 如果失败 - 向所有节点发送 DEL 释放锁包括加锁失败的节点解锁步骤向所有 N 个节点发送释放命令Lua 脚本验证 value if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) end return 0时间线示意├─── ttl 30秒 ───────────────────────────┤ │ │ T1────────T2──────────────────────────────────────────→ 锁过期 │ 加锁耗时 │ 锁实际可用时间 │ │ elapsed │ ttl - elapsed │ │ 200ms │ 29.8秒 │三、为什么需要多数成功多数派Quorum原理这是分布式系统的经典思想同样用于 Raft、Paxos、ZAB 等共识算法5个节点中任意 3 个构成多数派 客户端A 加锁成功节点 1, 2, 3 客户端B 加锁尝试 - 节点 1已有锁 → 失败 - 节点 2已有锁 → 失败 - 节点 3已有锁 → 失败 - 节点 4加锁成功 - 节点 5加锁成功 成功 2 个 多数(3) → 加锁失败 ✅ 互斥保证任何两个多数派至少有一个交集节点——这保证了两个客户端不可能同时获得多数派。节点宕机的容错5 个节点允许 2 个同时宕机N5, 多数3, 容错2 3 个节点允许 1 个同时宕机N3, 多数2, 容错1公式容错数 N - (N/2 1) (N-1)/2节点数 N多数容错321532743四、关键约束条件1. 节点必须独立✅ 正确5 个独立的 Redis 实例单机模式 ❌ 错误1 个 Redis Cluster 的 5 个主节点 ❌ 错误5 个 Redis Sentinel 的 5 个主节点RedLock 要求每个节点是完全独立的没有主从复制关系。如果用 Cluster/Sentinel它们内部的主从同步问题依然存在。2. 时钟假设RedLock 依赖一个假设各节点的时钟漂移在可接受范围内。如果某个节点时钟突然跳变NTP 校时跳跃可能导致锁提前过期节点3 时钟突然快了 20 秒 → 锁在节点3 上提前 20 秒过期 → 如果其他节点也到期了锁可能失效3. 加锁时间必须远小于 TTLttl 30 秒 加锁耗时 elapsed 200ms 锁有效时间 30 - 0.2 29.8秒 ✅ 充裕 如果网络延迟导致 elapsed 28秒 锁有效时间 30 - 28 2秒 ❌ 几乎没用 → 应该视为加锁失败五、代码示例Redisson 实现ConfigurationpublicclassRedLockConfig{BeanpublicRedissonClientredisson1(){ConfigconfignewConfig();config.useSingleServer().setAddress(redis://redis-node1:6379);returnRedisson.create(config);}BeanpublicRedissonClientredisson2(){ConfigconfignewConfig();config.useSingleServer().setAddress(redis://redis-node2:6379);returnRedisson.create(config);}BeanpublicRedissonClientredisson3(){ConfigconfignewConfig();config.useSingleServer().setAddress(redis://redis-node3:6379);returnRedisson.create(config);}}ServicepublicclassPaymentService{ResourceprivateRedissonClientredisson1;ResourceprivateRedissonClientredisson2;ResourceprivateRedissonClientredisson3;publicvoiddeductBalance(StringaccountId,BigDecimalamount){// 从 3 个独立 Redis 节点各获取一把锁RLocklock1redisson1.getLock(lock:account:accountId);RLocklock2redisson2.getLock(lock:account:accountId);RLocklock3redisson3.getLock(lock:account:accountId);// 组合为 RedLockRLockredLockredisson1.getRedLock(lock1,lock2,lock3);try{// 尝试加锁等待10秒持有30秒booleanacquiredredLock.tryLock(10,30,TimeUnit.SECONDS);if(!acquired){thrownewBusinessException(获取锁超时);}// 临界区accountRepository.deduct(accountId,amount);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}finally{redLock.unlock();}}}手动实现理解原理publicclassSimpleRedLock{privatefinalListRedisTemplateString,StringredisNodes;privatefinalintquorum;// 多数 N/2 1publicSimpleRedLock(ListRedisTemplateString,Stringnodes){this.redisNodesnodes;this.quorumnodes.size()/21;}publicbooleantryLock(StringlockKey,StringrequestId,longttlMs){longstartTimeSystem.currentTimeMillis();intsuccessCount0;// 依次在每个节点加锁for(RedisTemplateString,Stringnode:redisNodes){try{Booleanresultnode.opsForValue().setIfAbsent(lockKey,requestId,ttlMs,TimeUnit.MILLISECONDS);if(Boolean.TRUE.equals(result)){successCount;}}catch(Exceptione){// 节点不可用跳过}}longelapsedSystem.currentTimeMillis()-startTime;// 判断多数成功 且 耗时未超过 TTLif(successCountquorumelapsedttlMs){returntrue;// 加锁成功}else{// 失败释放所有节点的锁unlock(lockKey,requestId);returnfalse;}}publicvoidunlock(StringlockKey,StringrequestId){Stringscriptif redis.call(get,KEYS[1]) ARGV[1] then return redis.call(del,KEYS[1]) else return 0 end;for(RedisTemplateString,Stringnode:redisNodes){try{node.execute(newDefaultRedisScript(script,Long.class),Collections.singletonList(lockKey),requestId);}catch(Exceptione){// 节点不可用忽略}}}}六、RedLock 争议Martin Kleppmann 的批评分布式系统专家 Martin Kleppmann 发表文章“How to do distributed locking”指出 RedLock 的问题问题1GC 停顿导致锁失效时刻T1: 客户端A 获得 RedLockTTL30秒 时刻T2: 客户端A 发生 Full GC暂停 35 秒 时刻T3: 锁已过期30秒到了 时刻T4: 客户端B 获得同一把 RedLock 时刻T5: 客户端A GC 结束以为自己还持有锁 → 两个客户端同时操作问题2时钟跳变时刻T1: 客户端A 在节点 1,2,3 加锁成功TTL30秒 时刻T2: 节点1 时钟跳变NTP 向前调了 30 秒 时刻T3: 节点1 上的锁过期了实际才过了几秒 时刻T4: 客户端B 在节点 1,4,5 加锁成功 → 互斥失效他的建议如果锁仅用于效率优化避免重复工作单 Redis 节点就够了偶尔失效可接受。如果锁用于正确性保证数据一致性应该用fencing token递增令牌客户端获取锁时同时获得一个递增 token 写入存储时携带 token 存储端拒绝 token 小于当前值的写入 客户端A: token33GC暂停... 客户端B: token34写入成功 客户端A: GC恢复token33 34 → 写入被拒绝 ✅AntirezRedis 作者的回应GC 停顿问题所有分布式锁都有这个问题不是 RedLock 特有的时钟跳变合理的运维可以避免大幅跳变渐进式 NTP 校时RedLock 在合理假设下是正确的争议总结观点Martin KleppmannAntirezRedLock 安全吗不够安全依赖时钟假设在合理假设下安全推荐方案需要正确性用 ZooKeeper fencing tokenRedLock 足够大多数场景适用性RedLock 不比单节点强多少RedLock 明显强于单节点七、什么时候该用/不该用 RedLock适合用 RedLock金融级场景支付扣款、余额操作库存操作防止超卖对互斥性要求高但能接受极端情况下的短暂失效已有多个 Redis 实例的基础设施不需要 RedLock普通业务防重单 Redis 节点 幂等兜底即可效率型锁避免重复计算偶尔失效无业务影响缓存击穿保护单节点锁足够应该用 ZooKeeper 而非 RedLock强一致性要求不允许任何双写的场景Leader 选举分布式协调配置分发、服务发现八、替代方案对比方案一致性性能复杂度容错单 Redis 锁弱主从切换可能丢最高最低无RedLock中依赖时钟假设高中N/2 节点宕机ZooKeeper 锁强ZAB 协议共识中中N/2 节点宕机etcd 锁强Raft 协议共识中高中N/2 节点宕机数据库锁强事务保证低低依赖数据库高可用九、实际项目中的选择建议┌─ 效率型防重复工作→ 单 Redis 节点 │ 需要分布式锁 ───────┼─ 一般业务订单、库存→ 单 Redis 幂等兜底 │ 或 Redisson 普通锁 │ └─ 强一致资金、对账→ ZooKeeper / etcd 或 RedLock fencing token大多数业务场景Redisson 普通锁 业务层幂等就足够了。RedLock 适合在已有多 Redis 节点基础设施、且对互斥性有更高要求时使用。十、总结概念一句话RedLock在 N 个独立 Redis 节点上加锁多数成功才算成功多数派N/21 个节点同意 共识达成为什么需要单节点主从切换可能丢锁核心假设节点间时钟漂移在可接受范围内争议点GC停顿和时钟跳变可能导致失效实际建议大多数场景单节点锁幂等即可极端场景考虑 ZooKeeper

相关新闻

三步搞定机箱风扇噪音:FanControl 最省心的 Windows 风扇控制方案

三步搞定机箱风扇噪音:FanControl 最省心的 Windows 风扇控制方案

三步搞定机箱风扇噪音:FanControl 最省心的 Windows 风扇控制方案 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_…

2026/8/15 0:59:48 阅读更多 →
淘宝上架软件:isTrusted事件级伪装,平台风控视为真人操作

淘宝上架软件:isTrusted事件级伪装,平台风控视为真人操作

淘宝上架软件:isTrusted事件级伪装,平台风控视为真人操作 店群运营的本质不是开多少店,而是单店运营成本能不能压到零。淘宝的自动化上架,是店群运营中最耗人力也最容易出错的环节。 手动上架一个商品从填写标题、上传主图、设置…

2026/8/16 1:01:37 阅读更多 →
拼多多防关联系统:C++底层指纹伪装,抹除自动化特征

拼多多防关联系统:C++底层指纹伪装,抹除自动化特征

拼多多防关联系统:C底层指纹伪装,抹除自动化特征 说句掏心窝的话,做店群的,工具选对了事半功倍。拼多多的多店防关联管理,是店群运营中最耗人力也最容易出错的环节。 做店群的老板都知道,最怕的就是底层I…

2026/8/15 0:59:48 阅读更多 →

最新新闻

一人公司如何用AgentOS构建自动化数字飞轮:架构设计与实战

一人公司如何用AgentOS构建自动化数字飞轮:架构设计与实战

1. 项目概述:一人公司的数字飞轮如何转动最近和几个独立开发者朋友聊天,大家普遍有个共鸣:一个人单打独斗做项目,精力太容易被琐事耗散。今天要处理服务器告警,明天要回复用户反馈,后天还得写更新日志。创意…

2026/8/16 3:09:53 阅读更多 →
DeepSeek Harness 深度解析:与 LangChain / LangGraph 的本质区别

DeepSeek Harness 深度解析:与 LangChain / LangGraph 的本质区别

前言:这篇文章带大家从它的现象来理解这几个概念,拥有抽象的能力,知识才会越学越快。 一、场景锚定:它们分别解决什么痛点? 先讲一个"中央厨房"的故事 想象你开了一家大型餐厅。 大模型(比如…

2026/8/16 3:09:53 阅读更多 →
基于Spring Boot的手工艺品销售网站设计与实现

基于Spring Boot的手工艺品销售网站设计与实现

1. 项目背景与意义随着互联网经济的蓬勃发展和消费者对个性化、文化内涵商品需求的日益增长,手工艺品市场正迎来新的发展机遇。传统手工艺品销售模式受限于地域、信息不对称和渠道单一,难以将优质作品高效地展示给广大消费者。本项目旨在设计并实现一个基…

2026/8/16 3:09:53 阅读更多 →
Java 学习打卡 2026.08.15

Java 学习打卡 2026.08.15

一.Arrays 数组工具类(重点)Arrays 是 Java 提供的数组专用工具包,不用自己手写复杂逻辑,直接调用方法操作数组,非常便捷。1. 第三种打印数组方式:Arrays.toString()之前打印数组需要手写循环,现…

2026/8/16 3:09:53 阅读更多 →
VSCode与Notepad++十六进制插件对比与二进制编辑实战指南

VSCode与Notepad++十六进制插件对比与二进制编辑实战指南

1. 为什么我们需要直接编辑二进制文件?在大多数开发者和技术爱好者的日常工作中,我们打交道的主要是文本文件。无论是写代码、配环境还是记笔记,我们都在与人类可读的字符打交道。但当你需要处理一个损坏的图片、分析一个未知格式的数据包、逆…

2026/8/16 3:09:53 阅读更多 →
从解释者到决策架构师:石油工程师的下一个十年

从解释者到决策架构师:石油工程师的下一个十年

数字化工作流程正在从根本上改变地下工作的本质。 人工智能和自动化正在减轻数据整合、处理和协调输入的负担,使技术团队能够聚焦于不确定性和运营背景。 可扩展的计算能力正在消除迭代限制,使团队能够测试多种合理情景,并识别哪些变量对其运…

2026/8/16 3:08:52 阅读更多 →

日新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/14 13:40:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/14 14:06:45 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/15 2:35:29 阅读更多 →