14人参与 • 2025-10-20 • Redis
好的,我们来详细、深入地探讨一下 redis 红锁(redlock)。
redlock 是 redis 官方提出的一种用于在分布式环境下实现强一致性分布式锁的算法。它的提出,是为了解决在 redis 主从复制或哨兵模式下,使用单实例 redis 锁可能遇到的锁失效问题。
在深入了解红锁之前,必须先理解它要解决什么问题。
假设我们使用单个 redis 实例实现分布式锁(通常用 set key random_value nx px 30000命令):
核心问题:在异步复制的场景下,锁数据在写入主节点后,到同步到从节点之间存在一个时间窗口。在这个窗口内主节点故障,会导致锁数据的丢失。
红锁的目标就是消除对单个 redis 实例的依赖,从而避免这类问题。
红锁的基本思想非常直观:“不要把所有鸡蛋放在一个篮子里”。
它要求客户端向一个独立的、无主从关系的 redis 实例集群中的多数(n/2+1)个节点依次申请锁,只有当从多数节点都获取锁成功,并且总耗时小于锁的有效时间,才算最终加锁成功。
部署多个 redis master 节点:这些节点必须是完全独立的,相互之间没有数据同步关系(例如,不是同一个哨兵或集群下的节点)。建议至少 5 个节点,这样可以容忍其中 2 个节点故障,从而保证系统的可用性。
假设我们有 n 个 redis 节点(例如 n=5)。
第一步:获取当前时间
客户端在开始获取锁之前,先记录一个开始时间 start_time。
第二步:依次向所有 n 个节点申请锁
客户端使用相同的键名和随机值,依次向 5 个 redis 实例发送锁申请命令(set lock_name my_random_value nx px 30000)。
为了减少因为某个节点故障而造成的长时间等待,可以为每个节点的请求设置一个远小于锁超时时间的网络超时时间(例如,锁超时 10 秒,网络超时 50-100 毫秒)。如果一个节点没有响应,应尽快尝试下一个节点。
第三步:计算获取锁的总耗时
当客户端从所有节点都收到响应(无论是成功还是失败)后,记录结束时间 end_time。计算总耗时:total_time = end_time - start_time。
第四步:检查锁是否获取成功
客户端需要同时满足以下两个条件,才认为锁获取成功:
n/2 + 1个节点(对于 5 个节点,就是 3 个)上成功获取了锁。total_time必须小于锁的自动释放时间(ttl)。例如,锁的 ttl 是 10 秒,而 total_time是 2 秒,那么是有效的。如果 total_time是 12 秒,则无效。为什么需要条件 2? 这是为了防止客户端在获取锁的过程中耗时太久,导致最早申请到的那些锁在客户端开始执行关键代码前就已经过期了。
如果锁获取失败:客户端必须向所有 redis 节点发起释放锁的请求(即执行 lua 脚本,检查随机值并删除锁)。即使某些节点返回失败(比如它本来就没加锁成功),也需要尝试释放,以确保清理现场。
释放锁的过程相对简单:客户端需要向第一步中尝试获取锁的所有 n 个节点发送释放命令。
释放命令必须使用 lua 脚本保证原子性:
if redis.call("get", keys[1]) == argv[1] then
return redis.call("del", keys[1])
else
return 0
end这样做是为了确保只有锁的持有者才能释放锁,避免误删其他客户端创建的锁。
redlock 自提出以来,就在分布式系统领域引发了激烈的讨论,特别是来自 martin kleppmann(《数据密集型应用系统设计》作者)的挑战。理解这些争议点对于正确使用红锁至关重要。
对系统时钟(时钟跳跃)的敏感性
gc pause(垃圾回收暂停)或进程暂停带来的安全性问题
场景(martin 描述的著名例子):
问题的本质:红锁(以及任何基于超时的锁)无法区分“客户端业务逻辑执行缓慢”和“客户端进程已崩溃”这两种情况。它依赖于超时机制,而超时机制在存在长时间进程暂停时就会失效。
解决方案的讨论:martin 提出需要使用一种能够在共享存储中留下“围栏令牌”(fencing token) 的锁服务。客户端在写数据时,需要检查一个单调递增的令牌,以确保自己的操作是在最新的锁状态下进行的。这实际上要求共享资源层(如 zookeeper、etcd)提供额外的协调能力。
考虑到上述争议,你应该在以下情况下考虑使用红锁:
替代方案:
特性 | 描述 |
|---|---|
目标 | 在分布式 redis 环境下实现一个更安全、强一致的分布式锁。 |
核心思想 | 向多个独立的 redis 主节点申请锁,遵循“多数派”原则。 |
优点 | 解决了单点 redis 和主从架构下因异步复制导致的锁失效问题。 |
缺点/争议 | 1. 对系统时钟漂移敏感。 |
适用场景 | 对锁的一致性要求非常高,且愿意为了一致性牺牲部分性能和增加复杂度的场景。 |
替代方案 | redis 主从锁(可接受风险)、zookeeper、etcd。 |
到此这篇关于redis中红锁的使用小结的文章就介绍到这了,更多相关redis 红锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论