Redis WATCH 失败时 MULTI 怎样重试
Redis WATCH 相关的重试,应从新一轮 WATCH、读取和计算开始,再执行 MULTI 与 EXEC。若 EXEC 因监视键变化返回 Null,这一批排队命令没有执行;只重新发送 MULTI 和旧的写入值,会把已失效的计算结果再次提交。WATCH 命令本身通常返回 OK,冲突一般是在 EXEC 时体现。
官方地址:https://redis.io/
先确认失败发生在 EXEC 条件提交
设想两个管理请求同时修改某个任务的并发额度。每个请求都读取当前额度,再根据自己的规则计算新值。WATCH 的作用是让提交附带条件:如果观察期间相关键被修改,就放弃这次提交,让调用方重新判断。它不阻止其他客户端写入,也不为当前请求排队获取互斥锁。
| 收到的结果 | 代表什么 | 处理方向 |
|---|---|---|
| WATCH 返回 OK | 已经登记监视 | 继续读取,尚未提交更新 |
| 事务命令返回 QUEUED | 命令已排队 | 不能据此报告业务完成 |
| EXEC 返回 Null | 监视条件未满足,事务未执行 | 重新观察、读取和计算 |
| EXEC 返回命令结果数组 | 事务已进入执行 | 还要处理数组中的命令错误 |
| 等待 EXEC 时连接断开 | 客户端可能不知道是否执行 | 按结果未知处理,不能直接当冲突重放 |
不同驱动会把协议层 Null 映射成不同结果。redis-py 的 Pipeline 通常会用 WatchError 表达监视失效;但它在监视期间遇到连接问题也可能抛出 WatchError,所以异常类型本身不足以证明服务端明确拒绝了事务。
每轮重新 WATCH 并读取最新值
正确的读改写顺序应在同一连接上完成。以额度键 demo:worker:limit 为例,先监视该键,然后读取现值并检查格式与业务范围;计算通过后才进入 MULTI,排队写入新值,最后提交 EXEC。所有影响决策的键都应纳入监视集合,不能只监视最后写入的键。
假设某轮读到 12,准备把额度增加 2;另一请求在这期间改成 20。如果本轮 EXEC 返回 Null,下一轮必须重读 20,并重新判断增加额度是否仍被允许。把先前算出的 14 直接重交,会覆盖另一请求的意图。若用户动作本来是“设置为 14”,也仍应重新判断权限、版本和业务条件,而非假装沿用旧读取就安全。

EXEC 无论成功还是因冲突放弃,原有监视都结束。新一轮要重新 WATCH。若在进入 MULTI 前就发现数据不合法或业务不允许更新,应结束监视并释放连接;已经进入事务但决定取消时,使用驱动提供的丢弃或重置机制。
用有限重试保护连接与请求预算
重试应包含明确的退出条件。例如给一次请求安排最多 4 次尝试,每次冲突后随机等待几毫秒,并随尝试次数增加等待上限。这个数值只是示例策略,不是 Redis 推荐常量,应按接口延迟预算和竞争程度选择。
每次尝试需要拥有自己完整的连接使用范围:取得专用连接,WATCH,读取,校验,计算,MULTI,排队,EXEC,再清理事务状态。退出连接使用范围后再等待,避免退避期间占着连接池资源。若业务校验失败、请求已取消或尝试次数用尽,就把相应结果返回调用方,不再继续循环。
可直接交给实现者的重试规则是:仅当明确识别到 EXEC 的冲突拒绝,才计入冲突次数并开启下一轮;下一轮不复用上轮读取值或排队命令;成功后退出循环;未知结果转入业务查询或幂等确认。请求总预算还应覆盖网络读写超时与退避时间,单纯限制循环次数并不等于限制总耗时。
驱动若提供 transaction() 便利方法,需要先看清其自动重试与等待设置。不要在它外层再套一个无条件重试器,否则多个重试层可能让实际执行次数超出预期。
把传输异常和命令错误分开处理
网络超时与 Null 冲突拒绝是两类结果。EXEC 可能已经送达并执行,而回包没有到达客户端;此时盲目重试“额度加 2”有可能再次增加。涉及跨服务通知、扣减或外部动作时,应使用业务请求标识及可查询的处理状态,不能仅凭重新读一次值推断这次请求是否执行过。
Redis 事务也不提供通用回滚。队列阶段的语法错误和执行阶段的类型错误,应该按各自语义处理;执行阶段某条命令失败,并不意味着之前执行成功的命令会撤销。把所有异常都归为 WATCH 冲突后再整批重放,会扩大问题。

在生产连接管理上,监视期间不要把同一连接交给其他请求。对 redis-py 可使用 Pipeline 的上下文管理和 reset 机制;其他驱动也应采用其事务专用连接约定。业务账号只授予实际所需命令和键空间权限,读写权限错误应直接修复配置,不应消耗冲突重试额度。
记录冲突并缩短观察窗口
建议分别记录尝试次数、明确冲突次数、耗尽次数、业务拒绝和结果未知;日志记录请求标识及键的业务分类即可,避免输出凭据或完整敏感值。如果冲突持续增加,应检查 WATCH 到 EXEC 之间是否夹了远程调用、较重计算或等待用户输入。
可提前完成与键值无关的准备工作,把观察窗口保留给读取、快速决策和提交。持续高竞争的单一热点,可以考虑原子命令或服务端函数等更适合的方式;这会改变实现方案,应单独评估,不是给 WATCH 增加无限重试就能解决。
上线前可在独立测试键上用两个连接制造冲突:让连接甲先 WATCH 并读取,连接乙修改键,再由甲提交。预期甲收到冲突拒绝且本轮队列未执行;随后甲重新观察并读取乙留下的值。还应分别覆盖业务拒绝、重试耗尽和传输异常。这里描述的是读者可执行的测试方法,并非本文已取得的运行结果。
常见问题
值改了以后又改回来,还可能触发冲突吗?
可能。WATCH 不是只在最后比较一次当前值与旧值;观察期间的修改会影响提交资格,不能把最终字符串相同当成没有冲突。
键过期会不会让 EXEC 放弃?
当前 Redis 的过期、淘汰等服务端修改也可能影响监视。旧版本存在差异,特别是 Redis 6.0.9 以前过期键的行为,排查时需要确认服务版本。
只重试 EXEC 可以吗?
不可以。冲突后旧事务和监视关系已经结束,必须重新 WATCH、读取和计算,再创建新事务。
有限重试解决的是明确的乐观并发冲突。它需要新读取、干净连接和可控预算;对命令失败或执行结果未知,应走各自的业务处理路径。
Redis WAIT 怎样确认副本复制进度
- 上一篇
- Redis WAIT 怎样确认副本复制进度
- 下一篇
- Redis INCRBYFLOAT 返回的小数为什么难以直接比较
-
- 数据库 · Redis | 41分钟前 | Redis · 故障恢复 · redis Lua脚本 EVALSHA NOSCRIPT SCRIPT LOAD SCRIPT FLUSH 脚本缓存
- Redis EVALSHA 怎样复用已加载脚本
- 203浏览 收藏
-
- 数据库 · Redis | 44分钟前 | redis 部署 函数库 FUNCTION LOAD FCALL
- Redis FUNCTION LOAD 怎样部署函数库
- 294浏览 收藏
-
- 数据库 · Redis | 46分钟前 | 排行榜 · redis ZREVRANK Sorted Set ZRANK 有序集合排名
- Redis ZRANK 与 ZREVRANK 怎样判断成员位置
- 114浏览 收藏
-
- 数据库 · Redis | 48分钟前 | redis count set 随机成员 SRANDMEMBER
- Redis SRANDMEMBER COUNT 怎样随机读取多个成员而不删除
- 443浏览 收藏
-
- 数据库 · Redis | 54分钟前 | redis streams 消费组 XGROUP CREATE MKSTREAM
- Redis XGROUP CREATE MKSTREAM 怎样为不存在的 Stream 建消费组
- 164浏览 收藏
-
- 数据库 · Redis | 16小时前 | Redis · 缓存 · redis TTL maxmemory-policy eviction
- Redis eviction 触发后为什么带 TTL 的键不一定先被删除
- 484浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 1029次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 1029次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1173次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1133次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 972次使用
-
- Redis Stream XTRIM 如何避免消费组积压无限增长
- 2026-09-12 501浏览
-
- Redis AOF rewrite 期间如何判断磁盘与内存压力
- 2026-09-12 501浏览
-
- Redis RDB 和 AOF 怎么按可接受数据丢失量选择
- 2026-09-08 501浏览
-
- Redis XAUTOCLAIM 之后为什么仍有 pending:JUSTID、PEL 与消息删除边界
- 2026-08-29 501浏览
-
- Redis SET 的 GET 与 KEEPTTL 怎么一起验收:旧值返回、续期与回滚边界
- 2026-08-20 501浏览

