Redis 方案:SET key value NX PX 30000 一条命令原子完成「不存在才设置 + 过期时间」——value 必须是持有者唯一标识(UUID),释放时用 Lua 脚本原子地「比对值再删除」,否则可能误删别人的锁(自己的锁已过期被他人获得后);过期时间导致的业务未执行完问题用看门狗续期(Redisson 默认 30s 锁每 10s 续)。ZK 方案:临时顺序节点——拿锁即建节点,序号最小者得锁,其余监听前一个节点;会话断开临时节点自动删除,天然解决死锁与续期问题,性能低于 Redis。数据库方案:唯一索引插入或 SELECT ... FOR UPDATE,简单但性能差,仅适合低并发。
深坑与争议:Redis 主从切换时锁丢失(锁写入主节点还没同步到从节点,主宕机从升主,第二客户端再拿同一把锁成功)——Antirez 提出 Redlock(多数派节点独立加锁),Martin Kleppmann 的著名反驳指出其依赖时钟假设且无法提供正确性保证,核心是分布式锁无法解决 GC 暂停/时钟跳变下的** Fencing** 问题:正确做法是配合 fencing token(单调递增的锁版本号),下游资源拒绝旧 token 的写。落地经验:能用乐观锁(CAS 更新)、唯一约束、MQ 串行化替代时就不要分布式锁。追问方向:可重入分布式锁的实现、锁粒度与热点(库存行级锁 vs 全局锁)、etcd/Consul 的锁机制差异。
(约 500 字)