分布式锁: Redisson红锁(RedLock)原理与实现细节


分布式锁是分布式系统的核心基础设施,但 单节点 Redis 锁在高可用场景下存在致命缺陷:当 Redis 主节点宕机时,从节点可能因异步复制未完成而丢失锁信息,导致多个客户端同时持有锁。为此,Redis 作者 Antirez 提出了 RedLock 算法,旨在通过多节点协作提升分布式锁的可靠性。本文将深入剖析 Redisson 中 RedLock 的实现原理、技术争议与最佳实践。


一、单节点 Redis 锁的局限性

1. 主从架构下的锁丢失问题

假设以下场景:

  1. 客户端 A 在 Redis 主节点成功获取锁。
  2. 主节点宕机,锁尚未同步到从节点。
  3. 从节点晋升为新主节点,此时客户端 B 也能获取同一把锁。
  4. 结果:客户端 A 和 B 同时持有锁,违反互斥性。

2. 异步复制的风险

Redis 主从复制默认异步,锁的写入可能在故障切换后丢失。


二、RedLock 算法核心思想

RedLock 的核心是通过 多个独立的 Redis 节点(至少 5 个)协作实现分布式锁。算法步骤如下:

1. 加锁流程

  1. 向所有节点发起加锁请求
    客户端依次向 N 个独立 Redis 节点发送加锁命令:

    SET lock_key <unique_value> NX PX <expire_time>
    
    • 使用相同的 Key 和唯一值(如 UUID + 线程ID)。
    • 设置合理的过期时间(通常为 10-30 秒)。
  2. 计算有效锁数量
    客户端统计成功获得锁的节点数。若 多数节点(≥ N/2 +1) 返回成功,则认为加锁成功。
    示例:N=5 时,至少需要 3 个节点成功。

  3. 计算锁的实际持有时间
    锁的最终有效时间 = 初始过期时间 - 加锁过程耗时。

    • 若实际持有时间过短(如剩余时间 < 业务执行时间),需立即释放锁。

2. 释放锁流程

向所有节点发送释放锁的 Lua 脚本(无论是否加锁成功):

if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end

三、Redisson 中 RedLock 的实现

1. 配置多节点 Redisson 客户端

需为每个独立 Redis 节点创建 RedissonClient 实例:

Config config1 = new Config();
config1.useSingleServer().setAddress("redis://node1:6379");
RedissonClient client1 = Redisson.create(config1);Config config2 = new Config();
config2.useSingleServer().setAddress("redis://node2:6379");
RedissonClient client2 = Redisson.create(config2);// ... 创建其他节点客户端RLock lock1 = client1.getLock("myLock");
RLock lock2 = client2.getLock("myLock");
RLock lock3 = client3.getLock("myLock");RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

2. 加锁的底层逻辑

调用 redLock.lock() 时,Redisson 内部执行以下步骤:

  1. 向所有节点并行发起加锁请求
    使用异步线程池同时向 N 个节点发送加锁命令。

  2. 统计成功加锁的节点数

    • 若成功节点数 ≥ 多数(如 5 节点需 ≥3),则加锁成功。
    • 否则,向所有节点发送解锁命令,并抛出 LockException
  3. 启动看门狗续期(可选)
    若未指定 leaseTime,Redisson 会为所有成功节点启动看门狗线程,定期续期锁。

3. 解锁流程

调用 redLock.unlock() 时:

  1. 向所有节点发送解锁命令
    即使某些节点加锁失败,也需尝试解锁。

  2. 处理部分节点失败
    若某些节点解锁失败(如网络问题),Redisson 会记录日志,但不会重试(需业务层处理)。


四、RedLock 的技术争议与应对策略

1. 争议点

1.1 时钟跳跃问题
  • 场景:若某 Redis 节点发生时钟跳跃(如 NTP 同步导致时间回拨),可能导致锁提前过期。
  • Redisson 的应对
    默认依赖 Redis 服务器的系统时间,建议禁用自动时钟同步(或在物理机环境运行)。
1.2 网络延迟与 GC 停顿
  • 场景:客户端因 GC 停顿或网络延迟,误判锁已释放。
  • 解决思路
    • 锁过期时间应远大于业务最大执行时间(如设置 30 秒,业务执行时间 ≤10 秒)。
    • 使用唯一 Token(unique_value)确保只有锁持有者能释放锁。
1.3 算法安全性争议

Martin Kleppmann 在 How to do distributed locking 中指出:

  • RedLock 依赖「系统模型假设」(如无时钟跳跃、无长时间 GC),在异步模型下无法保证绝对安全。
  • 推荐使用基于 ZooKeeper/etcd 的 CAS 操作 替代。

Antirez 的回应 Is Redlock safe?:

  • RedLock 在 实践中的大多数场景 下足够安全,但需权衡场景需求。

2. 使用建议

  • 适用场景:对锁的可靠性要求高,可容忍极低概率的锁失效(如非金融场景)。
  • 规避方案
    • 结合业务幂等性 + 状态机,即使锁失效也能保证最终一致性。
    • 使用 Fencing Token(递增令牌)防止过期锁操作资源(需存储层支持)。

五、RedLock 性能优化

1. 节点数量选择

  • 建议节点数:5 或 7(容错能力与性能的平衡)。
  • 容错能力公式:允许宕机节点数 = (N-1)/2。

2. 超时时间设置

  • 加锁超时:建议 50-200ms(避免长时间阻塞)。
  • 锁过期时间:业务最大执行时间的 2-3 倍。

3. 异步加锁优化

使用 tryLockAsync() 实现非阻塞加锁:

RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
RFuture<Boolean> future = redLock.tryLockAsync(100, 10, TimeUnit.SECONDS);
future.whenComplete((res, ex) -> {if (res) {// 加锁成功}
});

六、对比其他方案

方案优点缺点适用场景
Redis 单节点锁高性能、简单主从切换可能丢锁非关键业务、低并发
RedLock高可靠性(多节点容错)性能较低、实现复杂高可靠性要求
ZooKeeper 锁CP 模型、强一致性性能差、依赖 ZK 集群金融、政务系统
etcd 锁高并发、强一致性(Raft 协议)功能较简单Kubernetes 生态、高并发

七、总结

Redisson 的 RedLock 实现通过多节点协作,显著提升了分布式锁的可靠性,但其复杂性、性能损耗和潜在风险(如时钟问题)需谨慎评估。技术选型建议

  • 常规场景:优先使用单节点 Redis 锁(结合业务幂等性)。
  • 高可靠场景:评估 RedLock 或转向 ZooKeeper/etcd。
  • 混合方案:对关键资源使用 RedLock,非关键资源使用单节点锁。

最终,分布式锁的可靠性不仅依赖中间件,还需结合业务层的容错设计(如事务补偿、异步校对),才能构建健壮的分布式系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/905895.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++多态面试题之(析构函数与虚函数)

有以下问题展开 析构函数要不要定义成虚函数&#xff1f;基类的析构函数要不要定义成虚函数&#xff1f;如果不定义会有什么问题&#xff0c;定义了在什么场景下起作用。 1. 基类析构函数何时必须定义为虚函数&#xff1f; 当且仅当通过基类指针&#xff08;或引用&#xff09;…

Python高级进阶:Vim与Vi使用指南

李升伟 整理 在 Python 高级进阶中&#xff0c;使用 Vim 或 Vi 作为代码编辑器可以显著提升开发效率&#xff0c;尤其是在远程服务器开发或快速脚本编辑时。以下是关于它们在 Python 开发中的高级应用详解&#xff1a; 1. Vim/Vi 简介 Vi&#xff1a;经典的 Unix 文本编辑器…

Dify中使用插件LocalAI配置模型供应商报错

服务器使用vllm运行大模型&#xff0c;今天在Dify中使用插件LocalAI配置模型供应商后&#xff0c;使用工作流的时候&#xff0c;报错&#xff1a;“Run failed: PluginInvokeError: {"args":{},"error_type":"ValueError","message":&…

深度学习驱动下的目标检测技术:原理、算法与应用创新(二)

三、主流深度学习目标检测算法剖析 3.1 R - CNN 系列算法 3.1.1 R - CNN 算法详解 R - CNN&#xff08;Region - based Convolutional Neural Networks&#xff09;是将卷积神经网络&#xff08;CNN&#xff09;应用于目标检测领域的开创性算法&#xff0c;其在目标检测发展历…

【Umi】项目初始化配置和用户权限

app.tsx import { RunTimeLayoutConfig } from umijs/max; import { history, RequestConfig } from umi; import { getCurrentUser } from ./services/auth; import { message } from antd;// 获取用户信息 export async function getInitialState(): Promise<{currentUse…

[学习] RTKLib详解:qzslex.c、rcvraw.c与solution.c

RTKLib详解&#xff1a;qzslex.c、rcvraw.c与solution.c 本文是 RTKLlib详解 系列文章的一篇&#xff0c;目前该系列文章还在持续总结写作中&#xff0c;以发表的如下&#xff0c;有兴趣的可以翻阅。 [学习] RTKlib详解&#xff1a;功能、工具与源码结构解析 [学习]RTKLib详解…

移植RTOS,发现任务栈溢出怎么办?

目录 1、硬件检测方法 2、软件检测方法 3、预防堆栈溢出 4、处理堆栈溢出 在嵌入式系统中&#xff0c;RTOS通过管理多个任务来满足严格的时序要求。任务堆栈管理是RTOS开发中的关键环节&#xff0c;尤其是在将RTOS移植到新硬件平台时。堆栈溢出是嵌入式开发中常见的错误&am…

window 显示驱动开发-使用有保证的协定 DMA 缓冲区模型

Windows Vista 的显示驱动程序模型保证呈现设备的 DMA 缓冲区和修补程序位置列表的大小。 修补程序位置列表包含 DMA 缓冲区中命令引用的资源的物理内存地址。 在有保证的协定模式下&#xff0c;用户模式显示驱动程序知道 DMA 缓冲区和修补程序位置列表的确切大小&#xff0c;…

SD-HOST Controller design-----SD CLK 设计

hclk的分频电路&#xff0c;得到的分频时钟作为sd卡时钟。 该模块最终输出两个时钟&#xff1a;一个为fifo_sd_clk,另一个为out_sd_clk_dft。当不分频时&#xff0c;fifo_sd_clk等于hclk&#xff1b;当分频时候&#xff0c;div_counter开始计数&#xff0c;记到相应分频的时候…

完全背包问题中「排列数」与「组合数」的核心区别

&#x1f3af; 一句话理解 求组合数&#xff08;不计顺序&#xff09; → 外层遍历物品&#xff0c;内层遍历背包容量 求排列数&#xff08;计顺序&#xff09; → 外层遍历背包容量&#xff0c;内层遍历物品 &#x1f3b2; 举例说明 假设有硬币 [1, 2, 3]&#xff0c;目标金…

NHANES指标推荐:MDS

文章题目&#xff1a;The association between magnesium depletion score (MDS) and overactive bladder (OAB) among the U.S. population DOI&#xff1a;10.1186/s41043-025-00846-x 中文标题&#xff1a;美国人群镁耗竭评分 &#xff08;MDS&#xff09; 与膀胱过度活动症…

C++:字符串操作函数

strcpy() 功能&#xff1a;把一个字符串复制到另一个字符串。 #include <iostream> #include <cstring> using namespace std;int main() {char src[] "Hello";char dest[10];strcpy(dest, src);cout << "Copied string: " << …

1基·2台·3空间·6主体——蓝象智联解码可信数据空间的“数智密码”

近日&#xff0c;由全国数据标准化技术委员会编制的《可信数据空间 技术架构》技术文件正式发布&#xff0c;标志着我国数据要素流通体系向标准化、规范化迈出关键一步。该文件从技术功能、业务流程、安全要求三大维度对可信数据空间进行系统性规范&#xff0c;为地方、行业及企…

基于TI AM6442+FPGA解决方案,支持6网口,4路CAN,8个串口

TI AM6442FPGA解决方案具有以下技术优势及适用领域&#xff1a; 一、技术优势 ‌异构多核架构‌&#xff1a;AM6442处理器集成7个内核&#xff08;2xCortex-A534xCortex-R5F1xCortex-M4F&#xff09;&#xff0c;可实现应用处理、实时控制和独立任务分核协同&#xff0c;满足…

android vlc播放rtsp

最近在做IOT开发&#xff0c;需要把IOT设备的RTSP流在手机端播放&#xff0c;VLC是个不错的选择&#xff0c;使用起来简单方便。 1、在AndroidManifest.xml 中添加网络权限 <uses-permission android:name"android.permission.INTERNET"/> <uses-permissi…

前端面经 9 JS中的继承

借用Class实现继承 实现继承 extends super extends 继承父类 super调用父类的构造函数 子类中存在方法采取就近原则 &#xff0c;子类构造函数需要使用super()调用父类的构造函数 JS 静态属性和私有属性 寄生组合式继承

jQuery知识框架

一、jQuery 基础 核心概念 $ 或 jQuery&#xff1a;全局函数&#xff0c;用于选择元素或创建DOM对象。 链式调用&#xff1a;多数方法返回jQuery对象&#xff0c;支持连续操作。 文档就绪事件&#xff1a; $(document).ready(function() { /* 代码 */ }); // 简写 $(function…

【HCIA】BFD

前言 前面我们介绍了浮动路由以及出口路由器的默认路由配置&#xff0c;可如此配置会存在隐患&#xff0c;就是出口路由器直连的网络设备并不是运营商的路由器&#xff0c;而是交换机。此时我们就需要感知路由器的存活状态&#xff0c;这就需要用到 BFD&#xff08;Bidirectio…

前端流行框架Vue3教程:18. _组件数据传递

透传 Attributes 透传attribute指的是传递给一个组件&#xff0c;却没有被该组件声明为props或emits的attribute或者v-on事件监听器。最常见的例子就是class、style和id 当一个组件以单个元素为根作渲染时&#xff0c;透传的attribute会自动被添加到根元素上 透传 Attributes …

卓力达电铸镍网:精密制造与跨领域应用的创新典范

目录 引言 一、电铸镍网的技术原理与核心特性 二、电铸镍网的跨领域应用 三、南通卓力达电铸镍网的核心优势 四、未来技术展望 引言 电铸镍网作为一种兼具高精度与高性能的金属网状材料&#xff0c;通过电化学沉积工艺实现复杂结构的精密成型&#xff0c;已成为航空航天、电…