首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >两个服务同时抢一张订单怎么办?分布式锁三种方案对比

两个服务同时抢一张订单怎么办?分布式锁三种方案对比

原创
作者头像
上海魁鲸科技
发布2026-09-15 18:12:15
发布2026-09-15 18:12:15
390
举报

单机时代,一个 synchronized 就能挡住并发。系统拆成微服务之后,麻烦来了:两个实例同时抢到同一张订单、定时任务在三个节点上各跑了一遍、库存被两个请求同时扣减——进程内锁管不到别的机器,必须有把"全集群都认"的锁。

核心需求就一句话:在分布式环境里,让同一时刻只有一个节点能执行某段逻辑。 业界有三条主流路线:数据库锁、Redis 锁、Zookeeper/etcd 锁,可靠性、性能、复杂度各不相同。

方案一:数据库锁

原理: 用数据库的行锁或唯一约束实现。典型做法两种:select ... for update 悲观锁,或者建一张锁表、靠唯一索引插入成功即获锁。释放就是提交事务或删记录。

优点:

  • 零额外组件,项目里本来就有数据库
  • 语义直白,团队没有学习成本
  • 锁和业务数据同事务,一致性最省心

缺点:

  • 性能差:锁竞争激烈时,数据库连接被打满,拖累正常业务
  • 没有自动过期:持锁节点宕机,要靠超时清理机制兜底
  • 高并发场景顶不住,本质是拿最贵的资源干最粗的活

适用场景: 并发量不大、锁竞争不激烈的系统,或者锁逻辑和业务事务强绑定的场景(比如扣款时锁账户行)。小团队起步阶段的务实选择。

方案二:Redis 锁

原理:SET key value NX PX 原子命令加锁,value 存唯一标识,配合 Lua 脚本安全解锁。要更强可靠性就上 RedLock(多节点加锁)或直接用 Redisson 这类封装好的客户端,自带看门狗续期。

优点:

  • 性能最好:单节点十万级 QPS,锁操作微秒级
  • 自动过期:PX 过期时间天然防死锁
  • 生态成熟:Redisson 把续期、可重入、读写锁都封装好了

缺点:

  • 可靠性有天花板:主从切换时锁可能丢(刚写入主库还没同步,主库挂了),RedLock 缓解但不能根治
  • 续期逻辑要想清楚:业务执行超过锁时长,锁提前释放,并发冲突照来
  • 极端场景(长时间 GC 停顿)下可能出现"锁已过期但自己还以为持有"

适用场景: 绝大多数互联网业务场景:防重复提交、任务防重、库存扣减。性能优先、对极端小概率的锁失效能容忍(有幂等兜底)的场景,这是默认答案。

方案三:Zookeeper / etcd 锁

原理: 利用 ZK 的临时顺序节点:所有客户端在锁节点下创建临时顺序节点,序号最小的获得锁,其余监听前一个节点。客户端宕机,临时节点自动删除,锁自动释放。etcd 的 lease + revision 机制同理。

优点:

  • 可靠性最强:宕机自动释放、没有主从切换丢锁问题
  • 公平性:顺序节点天然是公平锁,先来先得
  • 羊群效应可控:只监听前一个节点,释放时不会惊起一片

缺点:

  • 性能低于 Redis:写操作要走共识协议,吞吐差一个量级
  • 运维成本:要维护 ZK/etcd 集群,团队要懂它的脾气
  • 客户端复杂度高,自行封装容易踩坑(用 Curator 等成熟库)

适用场景: 金融级强一致场景:资金结算、核心交易的并发控制。或者系统本来就有 ZK/etcd 基础设施,顺手用。单纯为锁引入 ZK 集群,多数团队不值当。

按可靠性需求对号入座

场景特征

推荐方案

并发不高、锁与业务事务强绑定

数据库锁

高并发、性能优先、有幂等兜底

Redis 锁(Redisson)

金融级强一致、已有 ZK/etcd 设施

Zookeeper / etcd 锁

一个务实的共识:锁负责挡大概率冲突,幂等负责兜小概率漏网。 不管选哪种锁,关键操作都该有幂等设计(唯一约束、去重表、状态机校验)兜底。把正确性完全押在锁上的系统,早晚出事。

落地前必做的三件事

第一件:明确锁的粒度和时长预期。 锁订单号还是锁用户?业务最长执行多久?这两个问题决定 key 设计和过期时间,也是后续所有坑的源头。粒度能小不大,时长按 P99 执行时间加缓冲。

第二件:锁失败要有明确策略。 抢不到锁是直接失败、排队等待还是稍后重试?不同业务答案不同:用户请求适合快速失败,后台任务适合重试。没定策略就上线,用户会看到莫名其妙的报错。

第三件:监控锁的健康度。 锁等待时长、获取失败率、锁持有时间分布,这些指标要进监控。锁竞争悄悄恶化是系统变慢的隐形推手,等用户投诉就晚了。

写在最后

分布式锁没有银弹:Redis 快但有极端场景的豁口,ZK 稳但重,数据库简单但慢。先想清楚业务能容忍什么——能容忍小概率冲突就选性能,不能容忍就选可靠性,但无论如何,幂等兜底都别省。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 方案一:数据库锁
  • 方案二:Redis 锁
  • 方案三:Zookeeper / etcd 锁
  • 按可靠性需求对号入座
  • 落地前必做的三件事
  • 写在最后
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档