☰
Redis分布式锁别瞎用,我的数据差点被覆盖
2026/10/5 13:32:59 网站建设 项目流程

上周三凌晨,我盯着监控面板上的订单数据心跳加速——10分钟内的库存扣减记录里,同一个SKU居然出现了6次重复扣减。事后排查发现,正是团队里那个"看似靠谱"的Redis分布式锁实现,在流量突增时放行了并发请求。今天我们就来解剖这个差点酿成大祸的"伪锁"。

一、现象:锁了,但没完全锁

当时我们的秒杀系统正在做全链路压测,QPS刚突破3k时,监控突然报警库存异常。查看Redis锁日志时发现了诡异现象:

[16:23:45] 客户端A 获取锁成功: order_1234 (TTL=30s) [16:23:46] 客户端B 获取锁成功: order_1234 (TTL=30s) <-- WTF?

两个不同的客户端,在1秒内先后拿到了同一个订单ID的锁。最终导致库存服务处理了完全相同的6个请求,商品超卖不说,财务对账时发现账户余额也出现了负数。

二、根因:自以为是的原子性

翻出当时"祖传"的锁实现代码,问题一目了然:

// 错误示范:三宗罪齐备的锁实现 public boolean tryLock(String key) { Long expireTime = System.currentTimeMillis() + 30000; if (redisTemplate.opsForValue().setIfAbsent(key, expireTime)) { // 罪1:非原子操作 redisTemplate.expire(key, 30, TimeUnit.SECONDS); // 罪2:非原子续期 return true; } Long oldExpireTime = (Long) redisTemplate.opsForValue().get(key); if (oldExpireTime != null && oldExpireTime < System.currentTimeMillis()) { redisTemplate.opsForValue().set(key, expireTime); // 罪3:竞态条件 return true; } return false; }

这段代码犯了三个致命错误:

  1. SETNX+EXPIRE非原子:两个命令之间如果进程崩溃,会导致死锁
  2. 时间校验不可靠:客户端时钟不同步时可能误判锁过期
  3. 删除校验缺失:解锁时不做value比对,可能误删其他客户端持有的锁

三、救火:从Redlock到红皮书方案

当时紧急回滚后,我们测试了三种解决方案:

方案吞吐量(QPS)强一致性复杂度
原生SET NX PX12k❌⭐
Redlock5k✅⭐⭐⭐
红皮书+续期线程8k✅⭐⭐

最终选择了《Redis设计与实现》推荐的改进方案:

// 正确姿势:Lua脚本保证原子性 String script = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then " + " redis.call('pexpire', KEYS[1], ARGV[2]) " + " return 1 " + "else " + " return 0 " + "end"; Boolean success = redisTemplate.execute( new DefaultRedisScript<>(script, Boolean.class), Collections.singletonList(lockKey), clientId, // 必须用唯一值 30000 );

关键改进点:

  1. 原子操作:用Lua脚本打包SETNX和EXPIRE
  2. 唯一标识:value使用clientId+线程ID,避免误删
  3. 续期机制:另起线程对未完成的锁定期续期

四、避坑指南:血泪换来的经验

  1. 时钟跳跃是大敌:NTP同步时可能导致锁提前过期,优先使用TTL而非时间戳
  2. 网络延迟会骗人:业务处理时间超过锁有效期时,CAP理论会教你做人
  3. 单点故障无解:Redis主从切换时的锁丢失问题,Redlock也救不了
  4. 锁重入要谨慎:相同线程重复获取锁时,Java的ReentrantLock思维会害了你

五、什么时候该用分布式锁?

经过这次事故,我们定下新规范:

  • 读多写少场景 → 直接用CAS
  • 低频写操作 → 数据库乐观锁
  • 高频写且允许少量偏差 → 本地锁+延时队列
  • 必须强一致时→ Redis锁+Zookeeper备份

现在看监控面板上的锁争用指标时总会多瞄两眼——你在项目里是怎么处理分布式锁的?有没有遇到过更诡异的锁失效案例?评论区聊聊你的实战经历。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询