当前位置:首页 > 文章列表 > 数据库 > Redis > Redis SETNX 分布式锁为什么会误删:令牌校验、过期与释放脚本

Redis SETNX 分布式锁为什么会误删:令牌校验、过期与释放脚本

来源:17golang原创 2026-08-24 15:28:47 0浏览 收藏

订单超时任务偶尔会同时跑两次,排查 Redis 记录时却发现锁明明存在过。最容易忽略的情况是:持锁进程暂停超过租约,新进程已经拿到同一个锁,旧进程恢复后执行一条无条件 DEL,把新进程的锁也删掉了。

日常开发里用SETNX做Redis分布式锁,很容易碰到自己的任务卡了几秒、最后顺手删掉了别人刚拿到的锁的情况,问题根源根本不是SETNX本身有bug,而是锁的所有权校验、原子操作边界、过期规则这几块没做对。

实践要点

  • SETNX 只负责竞争,锁值必须放入每次任务独有的随机令牌。
  • 释放前要比对令牌,比较和删除必须由 Redis 原子完成。
  • 过期时间是兜底边界,不是续期和业务完成确认的替代品。
常见的误删场景里,绝大多数情况都是没做锁持有者身份校验,直接用DEL命令删锁,或者校验令牌和删锁的两步操作中间插入了别的调度逻辑,最后动了不属于当前进程的锁。

先把误删现场还原出来

假设锁键是 lock:order-timeout。进程 A 抢到锁后暂停,租约 10 秒到期;进程 B 随后抢到锁并写入自己的令牌。此时 A 恢复,若仍执行 DEL lock:order-timeout,B 的任务就失去了互斥保护。

Redis 分布式锁误删竞态:旧持有者 A 延迟释放,新持有者 B 已经写入令牌

这条时间线里,A 的删除动作在语法上完全成功,但在所有权上已经失效。日志只记录“删除返回 1”并不能证明删除的是自己的锁,必须把令牌和持有者一起记录下来。

加锁时同时写入随机令牌和租约

Redis 版本支持 SET 的 NX 与 EX 组合时,优先使用一条命令完成抢锁和设置过期时间:

SET lock:order-timeout 7f3c...a91 NX EX 10

返回 OK 才代表本次任务拿到锁;返回空值表示已有持有者。令牌可以使用 UUID 或安全随机串,不能用固定的主机名、进程名,也不要让所有任务共用一个值。

为什么不建议分成两条命令

先 SETNX、再 EXPIRE 存在中间崩溃窗口:锁已经写入,却没有租约,最后变成永久占用。即便业务还在使用旧写法,也要把设置过期时间的失败纳入告警和人工清理流程。

释放锁要把比较和删除绑在一起

下面的 Lua 脚本把“读取当前值、比较令牌、删除键”放进一次 Redis 脚本调用。只有值仍然等于自己的令牌时,删除才会发生:

if redis.call('get', KEYS[1]) == ARGV[1] then
  return redis.call('del', KEYS[1])
end
return 0

在客户端中执行脚本时,KEYS[1] 传入锁键,ARGV[1] 传入本次任务保存的令牌。返回 1 表示确实释放了自己的锁,返回 0 可能意味着锁已经过期、被续期逻辑改变,或当前持有者不是自己;这三种情况都不应再补一条无条件删除。

Redis 分布式锁安全释放:读取令牌、比较所有权后原子删除

续期和业务耗时要分开验收

任务耗时可能超过初始 10 秒时,可以按固定周期续期,但续期同样必须先校验令牌。否则 A 的续期请求在租约到期后到达,也可能延长 B 的锁。

if redis.call('get', KEYS[1]) == ARGV[1] then
  return redis.call('expire', KEYS[1], ARGV[2])
end
return 0

续期周期要明显短于租约,并给暂停、网络抖动和 Redis 响应延迟留出余量。更重要的是,业务完成后仍要走带令牌校验的释放脚本,不要把“任务执行成功”误当成“当前进程仍拥有锁”。

用可复查命令做一次小实验

可以在测试实例中手工验证所有权边界。先让 A 写入令牌:

SET lock:order-timeout token-a NX EX 5
GET lock:order-timeout
TTL lock:order-timeout

等待过期后让 B 写入 token-b,再用 A 的令牌调用释放脚本,结果应为 0,且 GET lock:order-timeout 仍然返回 token-b。最后用 B 的令牌调用同一脚本,结果才应为 1。

几个容易误判的结果

  • TTL 返回 -2 只表示键已不存在,不能证明某个进程释放成功。
  • 脚本返回 0 不等于 Redis 故障,先查看当前令牌和任务日志。
  • 集群模式下,脚本涉及的锁键应保持在同一个哈希槽;不要把无关键塞进同一脚本。

常见问题与上线前检查

放在当前任务的内存变量中,并把任务编号写入结构化日志。不要把令牌放在全局固定配置里,否则多个任务无法区分所有权。

令牌应该放在哪里?

不能把租约当成业务授权。进程发现续期失败或租约已经失效后,应停止会产生副作用的后续动作;无法中止时,业务写入还需要幂等键或版本校验兜底。

过期后还能继续做业务吗?

确认加锁使用 NX 与过期时间,令牌每次唯一;释放和续期都通过令牌校验脚本;日志能区分抢锁、续期、释放的返回值;最后用 A/B 两个令牌复查“旧持有者不能删除新持有者”。

Redis 分布式锁的安全边界不在“有没有 SETNX”,而在每个动作是否持续证明自己仍是持有者。把令牌校验放进 Redis 原子脚本,再用幂等和版本检查承接租约失效,才算完成一条可验收的并发控制链路。

上线前检查什么?

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
多模态模型图片输入怎么做尺寸校验:压缩、像素上限与失败重试多模态模型图片输入怎么做尺寸校验:压缩、像素上限与失败重试
上一篇
多模态模型图片输入怎么做尺寸校验:压缩、像素上限与失败重试
Google 同态加密如何让私有 AI 可用:开发团队该看懂的技术边界
下一篇
Google 同态加密如何让私有 AI 可用:开发团队该看懂的技术边界
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    383次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    454次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    467次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    407次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    237次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码