Skip to content

P09 分布式集群架构下怎么保证并发安全 ​

面试题:系统部署了多个实例(集群),原来单机上的 synchronized/Lock 还管用吗?怎么保证并发安全?

核心:单机锁在集群下失效 ​

synchronized、ReentrantLock 锁的是单个 JVM 内的对象,集群里有多个 JVM,各自持有一把锁,锁不住其他实例的线程。所以需要跨进程的互斥机制。

常用方案 ​

1. 分布式锁 ​

  • Redis 分布式锁(SETNX + 过期时间 + Lua 释放),或直接用 Redisson:
    • 注意:要设置过期时间防止死锁;释放时校验 value 防止误删;高可用可用 Redlock/红锁(一般不用);
  • Zookeeper 分布式锁(临时顺序节点 + Watch):
    • 强一致、无过期时间问题,但性能不如 Redis,适合对一致性要求高的场景;
  • 场景:抢单、扣库存、任务调度(分布式定时任务只让一台执行)。

2. 数据库层保证(最强兜底) ​

并发安全最终要以数据库为准:

  • 乐观锁:UPDATE ... SET version = version + 1 WHERE id = ? AND version = ?;
  • 条件更新:扣库存用 SET stock = stock - 1 WHERE id = ? AND stock > 0;
  • 唯一索引:防止重复插入(重复下单、幂等)。

3. 原子操作前置化 ​

把高频并发操作放到 Redis 用 Lua 脚本原子执行(判断 + 扣减一步完成),再异步落库,数据库只做最终校验。

4. MQ 串行化 ​

同一业务维度(同一用户、同一订单)的消息路由到同一个队列/分区,消费端串行处理,天然避免并发冲突。

设计原则 ​

  1. 能无锁就无锁:用不可变对象、ThreadLocal、单线程化(如 Disruptor/队列)规避;
  2. 锁的范围尽量小:只锁必要资源(如按 userId 分片加锁),避免全局锁拖垮吞吐;
  3. 最终一致性兜底:并发控制解决"抢",数据库约束解决"错";
  4. 幂等设计:重试、重复请求不产生副作用。

一句话总结 ​

集群并发安全靠"分布式锁做互斥 + 数据库乐观锁/唯一约束做兜底 + MQ/分片串行化降并发冲突",并优先考虑无锁化设计。

基于 VitePress 重建