Skip to content

你说你项目上用了分布式锁,加锁后并发度不就降低了吗? ​

  • 标签:后端、场景题

🏛 业务架构师 ​

面试官这个反问问得对,我承认:加锁必然降低并发度,分布式锁把并行变串行。但我的回答是:这是用吞吐换正确性,而正确性(不超卖、不重复扣款)是业务底线,不能交易。关键在于把锁的代价控制到最小。

降低锁影响的四个手段

1. 锁粒度最小化(最重要) 锁"这一件商品的这个用户",而不是锁整个下单接口:

  • 库存扣减:按 SKU 加锁(或乐观锁版本号),不同商品互不影响
  • 防重复操作:按用户 ID 加锁
  • 反面案例是全局锁一把梭——千级 QPS 直接变几十

2. 锁内只做关键判断 把慢操作全部挪到锁外:锁内只做"查库存→判断→扣减"的原子段,短信通知、数据同步、缓存刷新全部异步化。临界区从 200ms 压到 5ms,并发损失缩小 40 倍。

3. 能不用锁就不用锁

  • 数据库乐观锁:UPDATE stock SET num=num-1 WHERE sku=? AND num>0,利用行锁原子性,冲突场景少时吞吐远好于分布式锁
  • 幂等设计:用唯一索引挡重复请求,比锁便宜且绝对可靠
  • Redis 原子操作:DECR 扣库存天然原子,零显式锁

4. 业务分级,按资损决定锁的必要性

  • 资金/库存类:锁 + 幂等 + 对账,三重保险
  • 普通写操作:幂等就够
  • 统计计数:连幂等都可以省

收尾:我的原则是分布式锁只用于"正确性必须串行"的场景,并且评审时必问两个问题:锁的粒度能不能再小?这把锁能不能换成数据库约束?锁是手段,不是架构能力——不加锁还能保证正确,才是更好的设计。

🏗 系统架构师 ​

这个质疑本身是对的——锁就是把并行变串行,我要做的是把锁的代价压到业务可接受,并论证"不加锁的代价更大"。

第一层:先讲清锁保护的临界区有多小 以库存扣减为例:SETNX 抢锁 → 扣库存(一条 UPDATE,1~5ms)→ 释放锁。锁内只有一次 DB 操作,单把锁的理论串行上限是 200~1000 TPS。如果热点商品秒杀 10 万 QPS,确实不可接受——所以我不会用一把全局锁。

第二层:优化锁的粒度与并发度(核心)

  1. 锁粒度细化:全局锁 → 商品级锁 → SKU 级锁,锁对象带业务 key(lock:sku:{id}),不同 SKU 完全并行,整体并发 = 锁数量 × 单锁 TPS
  2. 锁内逻辑瘦身:参数校验、数据组装、RPC 全放锁外,锁内只留状态变更
  3. 乐观锁替代:冲突率低的场景用版本号 CAS,UPDATE ... WHERE version=?,无冲突时零锁开销;冲突高再用悲观分布式锁
  4. 彻底消灭锁:热点场景用 Redis DECR 原子预扣 + 异步落库(秒杀的经典做法),把 DB 行锁也绕开;或者队列串行化削峰

第三层:业务视角的权衡 锁降低并发度,但换来的是不超卖、不重复发券这类资损级正确性。正确性优先于性能是原则;性能问题用"细化粒度 + 热点拆分 + 异步化"解决,而不是裸奔。我的总结:先问锁内能不能变短、锁能不能变小、能不能不用锁,三步之后剩下的串行就是业务必须付的成本。

💻 全栈开发专家 ​

面试官在挑战锁的开销,我承认开销,然后讲我怎么把锁的粒度和范围压到最小——锁得准比不用锁更重要。

我的三层化解

  1. 缩小临界区:锁内只做"读余额/校验/扣减"三步,参数校验、数据组装、发消息全放锁外;耗时操作(HTTP 调用)绝不进锁。Redisson 的 watchdog 续期默认 30s,锁内逻辑必须远小于这个时间。

  2. 缩小锁粒度:锁订单号不锁用户 ID,锁库存 SKU 不锁整场活动——并发单元越细,并行度越高:

java
RLock lock = redisson.getLock("stock:" + skuId); // 而不是 "order:create"
  1. 热点 key 分段锁:单个 SKU 百万 QPS 时,把库存拆成 N 段(如 100 段),用户 hash 到某段扣减,锁竞争瞬间除以 100,末段不足时再做段间"借库存"——这就是分段锁/库存分桶方案。

更进一步:消灭锁

  • 能用数据库原子更新的不用分布式锁:UPDATE stock SET n = n - 1 WHERE sku=? AND n >= 1,影响行数即成败,行锁在 DB 内开销极小。
  • 能用 Redis Lua 的不用锁:扣减逻辑放脚本里原子执行。
  • 乐观锁(version/CAS)适合冲突低的场景,冲突激烈时重试成本反超锁。

一句话收尾 分布式锁是"用串行化换正确性"的手段,我的职责是让串行化的范围尽可能小、时间尽可能短,并监控锁等待时长指标来持续优化。