当前位置: 首页 > news >正文

“多数派”的智慧:Redis Redlock 分布式锁

1. Redlock 是什么?(概念篇)

通俗理解:多数人说了算的安全锁

想象一下,您有一份非常重要的文件(共享资源),需要确保在任何时刻都只有一个人能修改它(互斥)。这份文件放在一个由 5 个保险箱(Redis 实例)组成的大金库里。

  • 单机锁 (SET NX PX): 如果您只用其中一个保险箱来做锁,一旦这个保险箱突然坏了,持有钥匙的人可能永远拿不回来,或者别人误以为钥匙丢了,又造了一把新的,锁就失效了

  • Redlock (多数派锁): Redlock 的做法是:您要拿到 3 把以上(多数派) 保险箱的钥匙,才能算真正获得了这把锁。即使其中 1~2 个保险箱出了故障,只要您还能从大多数(3 个)保险箱那里证明您持有“锁凭证”,您的锁就是安全有效的。

核心思想: 不依赖单一节点的可靠性,而是依赖大多数节点达成共识。

学术定义:多实例的分布式锁算法

Redlock 是基于 N 个 独立的 Redis 主节点来构建分布式锁的算法。

  1. 目标: 在分布式环境中实现互斥(Mutual Exclusion)和活性(Liveness)。
  2. 方法: 客户端尝试在 大多数 (Majority) Redis 实例上获取锁,并确保这些操作在非常相似的时间内完成。
  3. 安全性提升: 它解决了单机锁在 Redis 主从切换、宕机或网络分区时,锁可能被多个客户端同时持有的安全隐患

2. 为什么需要 Redlock?(问题篇)

单机锁的不足与挑战

传统的 Redis 分布式锁通常依赖于一个命令:

SET key value NX PX milliseconds\text{SET} \ \text{key} \ \text{value} \ \text{NX} \ \text{PX} \ \text{milliseconds}SET key value NX PX milliseconds

这在单机模式下运行良好,但一旦引入高可用性(主从复制),问题就出现了:

挑战 1:主从异步复制导致的锁失效(安全漏洞)

客户端ARedis MasterRedis Slave客户端B初始状态:主从同步中1. SET lock_key A_random NX PX 100002. 锁L设置成功但未同步到SlaveOK3. Master 宕机!4. Slave 晋升为 New Master5. SET lock_key B_random NX PX 100006. 新的Master上无锁L客户端B成功获锁OK❌ 问题:A和B同时持有锁!互斥性被破坏!客户端ARedis MasterRedis Slave客户端B
  1. A 客户端Master 上成功设置了锁 L\text{L}L
  2. Master\text{Master}Master 在将 L\text{L}L 同步给 Slave 之前宕机了。
  3. Slave\text{Slave}Slave 被提升为新的 Master\text{Master}Master。此时,新的 Master\text{Master}Master 不包含L\text{L}L 的信息。
  4. B 客户端在新的 Master\text{Master}Master 上成功获取了同一个锁 L\text{L}L
  5. 结果: 锁被 A\text{A}AB\text{B}B 两个客户端同时持有,互斥性被破坏!

Redlock 的诞生就是为了解决这个致命的安全问题。通过要求客户端在 N/2 + 1 个独立节点上都成功设置锁,即使某个节点宕机并丢失了锁信息,只要大多数节点上的锁仍然存在,整个锁就是有效的,确保了安全性。


3. Redlock 怎么做?(解剖篇)

Redlock 算法要求部署 N 个 完全独立的 Redis 主节点(通常 N=5 )。以下是获取和释放锁的核心步骤,我们将结合实现逻辑来分析。

3.1 获取锁(Acquiring the Lock)

客户端执行以下步骤来获取锁:

在这里插入图片描述

步骤 1:时间戳记录

客户端记录当前时间 TstartT_{\text{start}}Tstart (毫秒)。

步骤 2:并行获取锁 (SET NX PX)

客户端尝试以串行或并行方式,依次向 NNN 个独立的 Redis 实例发送获取锁的命令。

SET resource_name random_value NX PX lock_validity_time\text{SET} \ \text{resource\_name} \ \text{random\_value} \ \text{NX} \ \text{PX} \ \text{lock\_validity\_time}SET resource_name random_value NX PX lock_validity_time

  • resource_name: 要锁定的资源键名。
  • random_value: 随机字符串,作为锁的“签名”,必须是全局唯一的。这是释放锁的关键凭证,防止 A 客户端释放了 B 客户端的锁(误释放)。
  • lock_validity_time: 锁的有效时间。这不仅是 TTL\text{TTL}TTL,也是获取锁成功的判断依据

步骤 3:计算时间差与判断多数派

客户端计算从开始获取到成功在至少 N/2+1\text{N}/2 + 1N/2+1实例上设置锁所花费的时间 TcostT_{\text{cost}}Tcost

Tcost=CurrentTime−TstartT_{\text{cost}} = \text{CurrentTime} - T_{\text{start}}Tcost=CurrentTimeTstart

判断成功的两个关键条件:

  1. 多数派成功: 客户端在 NNN 个实例中的 ≥N2+1\ge \frac{N}{2} + 12N+1 个实例上成功获取了锁。
  2. 时间有效性: 总耗时 TcostT_{\text{cost}}Tcost 必须小于锁的有效时间 lock_validity_time\text{lock\_validity\_time}lock_validity_time

如果满足以上两个条件,客户端认为获取锁成功

步骤 4:计算最终有效时间

一旦获取锁成功,锁的真正有效时间是:

Final_TTL=lock_validity_time−Tcost−Clock_Drift\text{Final\_TTL} = \text{lock\_validity\_time} - T_{\text{cost}} - \text{Clock\_Drift}Final_TTL=lock_validity_timeTcostClock_Drift

  • 为什么减去 TcostT_{\text{cost}}Tcost 因为在 Redis\text{Redis}Redis 实例中,锁的 TTL\text{TTL}TTL 是从 SET\text{SET}SET 命令执行那一刻开始计时的。客户端花费的时间越久,锁在 Redis\text{Redis}Redis 节点上剩下的时间就越少。Redlock 必须确保客户端拿到锁后,它在 Redis\text{Redis}Redis 上的剩余时间仍然有意义。
  • 为什么减去 Clock_Drift\text{Clock\_Drift}Clock_Drift (时钟漂移)? 这是一个额外的安全裕度,用于抵消不同服务器时钟不同步带来的风险。

如果最终 Final_TTL≤0\text{Final\_TTL} \le 0Final_TTL0,说明耗时太长,锁已经失效了,客户端应该认为获取锁失败,并立即进入释放锁的流程。

步骤 5:失败处理

如果获取锁失败(未达到多数派,或 Final_TTL≤0\text{Final\_TTL} \le 0Final_TTL0),客户端必须立即向所有实例(包括获取成功的那些)发送释放锁的命令(步骤 3.2),以防止“半锁”状态。

3.2 释放锁(Releasing the Lock)

释放锁相对简单,但必须确保安全性。客户端需要向所有 NNNRedis\text{Redis}Redis 实例发送 Lua\text{Lua}Lua 脚本来释放锁。

源码逻辑分析:为什么用 Lua 脚本?

释放锁的逻辑是原子操作,核心代码如下(抽象 Lua\text{Lua}Lua 脚本):

-- KEYS[1] 是资源的key
-- ARGV[1] 是客户端随机生成的 unique_value
if redis.call("GET", KEYS[1]) == ARGV[1] then-- 只有当存储的值等于客户端的 unique_value 时,才删除 keyreturn redis.call("DEL", KEYS[1])
else-- 值不匹配,不执行删除操作return 0
end

为什么必须检查 unique_value

客户端A客户端BRedis持有锁 (value=A_random)SET lock_key A_random NX PX 10000OK业务处理超时...锁因TTL到期自动释放SET lock_key B_random NX PX 10000OK成功获取锁尝试释放锁: DEL lock_key❌ 危险操作:如果直接DEL,会删除B的锁执行Lua脚本释放锁GET lock_key ->> B_random比较 B_random == A_random?比较结果: false返回 0 (释放失败)✅ 安全:B的锁被保护下来客户端A客户端BRedis

这是为了防止 A 释放 B 的锁(误释放):

  1. 客户端 A 获取了锁,设置 TTL=10s\text{TTL}=10sTTL=10svalue=A_random\text{value}=\text{A\_random}value=A_random
  2. A 业务处理时间过长(例如 20s),锁自动过期
  3. 客户端 B 在 15s 时成功获取了锁,设置 TTL=10s\text{TTL}=10sTTL=10svalue=B_random\text{value}=\text{B\_random}value=B_random
  4. A 客户端在 20s 时执行完业务,尝试释放锁。
  5. 如果不用 Lua\text{Lua}Lua 脚本检查 value\text{value}value,A 就会误删 B 设置的锁。
  6. 使用 Lua\text{Lua}Lua 脚本,A 释放时发现 GET\text{GET}GET 到的值是 B_random≠A_random\text{B\_random} \neq \text{A\_random}B_random=A_random释放失败,保证了 B 的锁的安全性。

释放流程: 客户端向所有 NNN 个实例发送这个 Lua\text{Lua}Lua 脚本,无论在这些节点上是否成功获取了锁(防止异常中断留下的残余锁)。


总结:Redlock 的本质与乐趣

Redlock 算法的乐趣在于,它没有引入复杂的分布式协调服务(如 Zookeeper 或 Consul),而是巧妙地利用了 Redis\text{Redis}Redis 单个实例的原子性 (SET NX PX) 和 多数派思想来对抗分布式环境中的网络分区节点宕机的风险。

  • 是什么: 基于 N\text{N}N 个独立 Redis\text{Redis}Redis 节点的多数派分布式锁算法。
  • 为什么: 解决单 Redis\text{Redis}Redis 实例在主从切换时,锁可能被多客户端同时持有的安全漏洞
  • 怎么做:
    1. ≥N/2+1\ge \text{N}/2 + 1N/2+1 个实例上 原子性 (SET NX PX) 地设置锁。
    2. 确保获取锁的总耗时 小于 锁的 TTL\text{TTL}TTL
    3. 使用 全局唯一随机值 作为锁的凭证。
    4. 使用 Lua\text{Lua}Lua 脚本 保证释放锁的 原子性安全性 (防止误释放)。

虽然 Redlock 在学术界存在一些争议(例如 Martin\text{Martin}Martin Fowler\text{Fowler}Fowler 的文章曾讨论过它的局限性,特别是在时钟同步和 Fencing\text{Fencing}Fencing Token\text{Token}Token 方面),但它无疑是目前 Redis\text{Redis}Redis 官方推荐的、易于理解和实现、且在多数场景下安全级别足够高的分布式锁方案。

http://www.dtcms.com/a/438788.html

相关文章:

  • 国家城乡建设官方网站参与做网站的收获
  • 房地产公司网站建设报价方案建立网站是什么建立的
  • 深圳网站建设公司佰达国内saas软件公司排名
  • P10806 [CEOI 2024] 洒水器 题解
  • 温州十大网络公司排名广州网站建设专业乐云seo
  • 做礼品的网站中航长江建设工程有限公司网站
  • SQL ROUND() 函数详解
  • RK3588 SSH相关方法总结(每次遇到问题更新)
  • 国家基础设施建设网站杨园建设社区网站
  • 3. 是网站建设的重点亿唐网不做网站做品牌原因
  • C# TCP 开发笔记(TcpListener/TcpClient)
  • 成都网络优化公司排行榜网站的优化是什么
  • 山西网站建设多少钱怎么做旅游网站
  • JAVA第八学:继承和多态
  • 网站开发前端指什么太原本地网站搭建公司
  • FastAPI 路径操作依赖项
  • wordpress开发网站美业营销策划公司
  • 《强化学习数学原理》学习笔记5——压缩映射定理的证明
  • Mysql速成笔记2(DML)
  • 网站流量如何增加东莞服务
  • pv-pvc-sc存储卷进阶-sts-helm资源清单基础管理
  • 什么是网站站点建设介绍网上营销新观察网
  • 吃透大数据算法-字典编码(Dictionary Encoding)
  • 从pty驱动学习tty设备驱动加载
  • 车牌号黑名单校验功能实现说明
  • 【第五章:计算机视觉-项目实战之生成对抗网络实战】2.基于SRGAN的图像超分辨率实战-(1)实战1:人脸表情生成实战任务详解
  • 【双指针专题】之快乐数
  • 锦州滨海新区城市建设规划网站建设局是个好单位吗
  • 域名搭建网站域名一般在哪里购买
  • 拦截器Interceptor