不要手写 redlock。官方 redlock-php 已停更,redis 官方不推荐;应使用 set key value nx px 原子命令加锁,配合唯一 value 和 lua 脚本解锁,并注意前缀、过期时间、异常释放等语义细节。

RedLock 在 PHP 里到底要不要自己手写
不要。官方 redlock-php 库已停止维护,且 Redis 官方明确不推荐客户端实现 RedLock —— 它对时钟漂移、网络分区等假设过于理想,实际集群中极易出现“双持有”锁。真正该做的是:用更简单、更可靠的方式达成「同一时刻只有一份执行」的目标。
PHP 集群加锁,优先用 Redis SET 命令的原子性
Redis 的 SET key value NX PX 30000 是当前最实用、最轻量的分布式锁基底。它天然原子,不依赖 Lua 脚本,兼容 Redis 2.6.12+,且能避免 SET + EXPIRE 的竞态问题。
-
NX确保只有 key 不存在时才设值(加锁成功) -
PX 30000指定毫秒级过期,防止死锁 - value 必须是唯一随机字符串(如
uniqid('', true)),用于解锁时校验所有权 - 解锁必须用 Lua 脚本:
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock_key client_id
为什么别碰 RedLock 的重试逻辑和多个 Redis 实例
RedLock 要求向 ≥3 个独立 Redis 节点发起 SET 请求,并在多数节点成功才算加锁成功。但 PHP 进程生命周期短、网络 I/O 不可控,极易出现:部分请求超时、时钟不同步导致过期误判、主从切换期间读到旧值 —— 这些都会让锁失效或误释放。
- 单 Redis 实例 + 正确的 SET+Lua 解锁,已覆盖 95% 的业务场景(如订单幂等、库存扣减)
- 真需要跨机房高可用?上 Redis Cluster 或云厂商的托管 Redis(如 AWS ElastiCache),而非自己拼 RedLock
- 若坚持多实例,至少禁用
read_timeout和connect_timeout的默认值,否则redlock-php的重试会卡住整个请求
PHP 使用 Redis 锁时最容易漏掉的三件事
不是语法错,而是语义错。很多线上事故都栽在这几个点上:
- 没给锁 key 加业务前缀,导致不同服务互相覆盖,例如都用
order_lock而不是order:pay:12345 - 锁过期时间远小于业务执行时间,又没做自动续期(
redis.setex()不等于续期,它会重置 TTL,但无法校验是否仍为当前客户端持有) - 异常分支里忘了释放锁,或用
DEL直接删(绕过所有权校验),导致其他进程误删锁
复杂点在于:锁只是手段,关键得和业务流程对齐。比如支付回调里加锁,要覆盖「查单 → 校验状态 → 更新 → 发通知」整条链路,而不是只锁住其中一步。这点容易被忽略,但决定了锁有没有实际意义。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











