首页/数据/Redis 进阶速查/WATCH 乐观锁实践
性能与排障129 条

WATCH 乐观锁实践

WATCH 监视键,EXEC 前若被改动则事务放弃(EXEC 返回空);循环重试是标准用法,适合低冲突的读改写场景。

Redis 进阶速查数据更新于 2026-10-13

WATCH 乐观锁是什么

WATCH 是 Redis 的乐观锁:先监视一个或多个键,再用 MULTI 开启事务,执行 EXEC 时如果被监视的键被其他客户端改过,事务就不执行、EXEC 返回空结果。标准用法是循环重试,适合冲突概率不高的读改写场景。

基本信息

流程WATCH 监视 → 读值 → MULTI → 写命令 → EXEC
冲突表现EXEC 返回空结果,事务未执行
解除监视UNWATCH,或 EXEC、DISCARD 之后自动清除
作用范围监视状态绑定在当前连接上
适用分布低冲突键;高冲突时改用 Lua 脚本或单命令原子操作

典型使用场景

  • 库存扣减:先读库存判断是否充足,事务内扣减,冲突就重试
  • 余额与流水一致:读改写期间防止其他写入插队
  • 配置更新:只在当前值仍符合预期时才写入
  • 缓存重建:未命中后写回,避免覆盖并发产生的新值
  • 重试策略验证:统计冲突率,据此决定是否更换方案
  • 集群注意:被监视的键与事务内的键必须落在同一分片

库存扣减示例

库存扣减示例
WATCH stock:1001          # 监视库存键
GET stock:1001            # 读当前值,判断业务条件是否满足
MULTI                     # 开启事务
DECR stock:1001           # 入队写入
EXEC                      # 键被改过则返回空,需要重新开始
UNWATCH                   # 本轮放弃时清除监视状态
# 客户端伪代码:循环 watch/read/multi/exec,EXEC 返回空就重试

EXEC 返回读法

返回含义处理方式
结果数组事务正常执行按顺序处理各条命令的结果
空结果被监视键已变化,事务放弃回到开头重试
错误入队或执行阶段出错按错误类型修正后重试
连接断开会话失效,监视状态丢失重建连接并清理客户端状态
重试要设上限并加退避:在高冲突键上无上限重试,延迟和失败率会一起被放大。
WATCH 与 EXEC 之间要尽量短:中间夹入慢命令或远程调用会显著抬高冲突概率,这也是要把读改写设计得足够轻的原因。

易错点

  • 不处理 EXEC 返回空的分支,事务没执行却按成功继续后续逻辑
  • 高冲突键上无上限重试,延迟放大甚至拖垮上游调用方
  • 监视之后夹入慢操作或外部调用,冲突率随等待时间上升
  • 集群环境里被监视的键与事务内键不在同一分片,事务直接报错

数据来源与参考

  • Redis 官方文档:WATCH 说明
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌