在线票务 / 抢票 架构模板
代表产品 / 原型:Ticketmaster、SeatGeek、大麦、12306,以及各类「秒杀」 一句话定位:在开售瞬间海量用户争抢有限的座位 / 库存时,保证不超卖、相对公平、系统不被冲垮。
1. 一句话定位
抢票系统 = 「极端瞬时并发」撞上「有限稀缺资源」的正面战场。
百万人在同一秒抢几万张票。它是 电商秒杀 的极致版,还多了一个维度:票常常是「具体的座位」(3 排 12 号只有一个)。它的全部设计,都在同时满足三件几乎冲突的事:绝不超卖、尽量公平、系统别崩。
2. 业务本质:它在解决什么问题
它把极度有限的资源(票 / 座位),在极度集中的时间(开售那一刻),卖给极度海量的人。
这件事的特殊性在于「开售即洪峰」:平时没流量,开售瞬间流量涨几千倍,几分钟后又归于平静。为这种尖刺做架构,和为「平稳增长」做架构,思路完全不同。
三条铁律,排好优先级:不超卖(底线)> 不崩(前提)> 公平(体验)。 卖出一张不存在的票,是事故;系统崩了,谁也抢不到;不公平,口碑崩塌。
3. 核心需求与约束
功能性需求:
- [ ] 放票 / 库存管理(可能精确到座位)
- [ ] 抢票:扣减库存 / 锁定座位
- [ ] 锁座(下单未支付时,先占住)+ 超时释放
- [ ] 下单、支付、出票
- [ ] 排队、限购、防刷
非功能性需求 / 质量属性:
| 质量属性 | 目标 | 为什么对这类系统重要 |
|---|---|---|
| 不超卖 | 绝对 | 卖出不存在的票是重大事故 |
| 峰值承载 | 抗住开售瞬间洪峰 | 平时低、开售瞬间爆,典型尖刺 |
| 公平 | 先到先得 / 防机器人 | 被黄牛脚本扫光,口碑崩 |
| 库存实时 | 余票 / 座位状态准 | 用户要看到「还剩几张」 |
关键约束(不可逾越的边界):
- 🔴 库存有限且精确:每个座位唯一,不能卖两次。
- 🔴 并发极端且瞬时:开售一瞬的写竞争集中在极少数「热门库存」上。
- 🔴 存在「锁定中」中间态:用户下单还没付,票既不能卖给别人、又不能永久占着。
- 🔪 黄牛 / 脚本:专业团伙用机器抢,公平性面临真实对抗。
4. 架构全景图
开售瞬间:百万用户涌入
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌──────────────────────────────────────────────┐
│ 虚拟等候室 / 排队(把洪峰挡在核心系统【外】) │
│ • 所有人先进等候室,拿一个排队号 │
│ • 按【系统能承受的速率】分批放行进入抢票 │
│ • 防刷:验证、限流、风控在这一层先筛一遍 │
└───────────────────────┬──────────────────────┘
▼ 放行令牌(细水长流,而非洪峰漫灌)
┌──────────────────────────────────────────────┐
│ 抢票 / 库存服务 │
│ • 库存【原子扣减】(热点库存放内存,绝不超卖) │
│ • 锁定座位(临时占位) │
└───────────────────────┬──────────────────────┘
▼ 抢到 → 生成订单(状态=待支付)
┌──────────────────────────────────────────────┐
│ 订单状态机 → 支付 → 出票 │
│ ⏰ 超时未支付 ──▶ 自动释放锁定的票,回到可售 │
└──────────────────────────────────────────────┘灵魂是最上面那层虚拟等候室:它的作用不是「让大家排队」,而是把洪峰挡在核心系统之外,按系统真实能力把流量「整形」成平稳水流。没有它,核心系统会在开售那一秒直接被冲垮。
5. 组件职责
- 虚拟等候室 / 排队:开售时所有人先进队列,按系统承载能力分批放行。为什么需要:这是抗洪峰的根本——保护核心系统不被瞬时流量打死(见决策 1)。
- 抢票 / 库存服务:用原子操作扣减库存,绝不超卖。为什么需要:防超卖是底线,普通的「读 - 改 - 写」在高并发下必然超卖(见决策 2)。
- 座位锁定:下单时临时占住座位,给用户支付时间。为什么需要:座位有「正在被某人买」的中间态。
- 超时释放:回收「占着不付」的锁定。为什么需要:否则票被占死,既卖不出也退不回(见决策 3)。
- 订单状态机:管「待支付 → 已支付 → 出票 / 取消」。为什么需要:出票关乎钱和库存,状态不能乱。
- 防刷风控:识别机器人 / 黄牛。为什么需要:公平性面临专业对抗。
6. 关键数据流
场景一:开售抢票(从洪峰到出票)
1. 开售,百万人涌入 ──▶ 全部进【虚拟等候室】,拿排队号
2. 系统按「每秒能处理 N 个」的速率,分批放行 ──▶ 进入抢票服务
3. 抢票:对热门场次库存做【原子扣减】
扣减成功 ──▶ 锁定座位,生成订单(待支付,给 10 分钟)
库存为 0 ──▶ 返回「已售罄」
4. 用户支付 ──▶ 出票,库存正式售出
5. ⏰ 10 分钟没付 ──▶ 自动释放,这张票回到可售池场景二:为什么不超卖(原子扣减)
✗ 错误:先查余量(读到 1)→ 两个请求都以为还有 → 都扣 → 卖出 2 张(超卖!)
✓ 正确:用【原子操作】「扣减并返回结果」,只有一个请求能把最后 1 张减成 0,
另一个原子操作返回「不足」 → 只卖出 1 张7. 数据模型与存储选择
核心实体:库存 / 座位(状态:可售 / 锁定 / 售出);订单(状态机);排队令牌。
| 数据 | 存储类型 | 为什么 |
|---|---|---|
| 热门场次库存 | 内存级 KV(原子操作) | 写竞争极热,数据库行锁扛不住瞬时洪峰 |
| 座位图 / 状态 | 内存 + 关系型落账 | 实时性要求高,最终要持久化 |
| 订单 | 关系型(强一致) | 关乎钱和出票,要事务 |
| 排队令牌 | 内存级 KV | 高频、易失 |
教学点:「热点库存」是个超级写热点——一个爆款场次的库存,瞬间被百万请求争抢同一行。把它放在内存级存储里做原子扣减,而不是让数据库的一行去扛,是抗住洪峰的关键。
8. 关键架构决策与权衡 ⭐
决策 1:虚拟等候室削峰(抗洪峰的根本)⭐
- 不削峰,让所有人直接打核心系统:开售瞬间核心系统被冲垮,谁也抢不到。
- 虚拟等候室:把人挡在门外排队,按系统能力放行。
- 取向:大型抢票必上等候室。把洪峰挡在门外,远比在门内拼命加机器有效——这是应对尖刺流量的第一性原理。
决策 2:库存扣减怎么保证不超卖?⭐
- 数据库「读余量 - 减余量 - 写回」:非原子,高并发下必然超卖。
- 数据库行锁 / 乐观锁:能防超卖,但热点行在洪峰下会成为瓶颈。
- 内存级原子扣减(单线程原子操作):又快又不超卖。
- 取向:并发不大用数据库行锁 / 乐观锁;热门洪峰场次用内存原子扣减,再异步落库。详见第 12 节。
决策 3:锁座的中间态——占而不付怎么办?⭐
- 不锁:用户选好座、还没付,被别人抢走 → 体验灾难。
- 锁了不设超时:占着不付,票永远卖不出去。
- 锁定 + 超时自动释放。
- 取向:必做「锁定 + 超时释放」。这是「临时持有稀缺资源」的通用模式——和分布式锁、库存预占同理。
决策 4:同步抢资格,异步走流程。
- 把「抢到资格(扣减库存)」做成同步、极快、原子;把后续「下单、支付」做成异步流程。
- 取向:核心争抢点越轻越快越好,把重活儿挪到抢到之后再慢慢做。
9. 规模化与瓶颈
- 第一个瓶颈:开售峰值。 → 破解:虚拟等候室削峰(根本手段)+ 前端静态化 + CDN。
- 第二个瓶颈:热点库存写竞争。 → 破解:热点库存放内存原子扣减;极热时分段库存(把 1000 张拆成 10 段各 100 张,分散竞争)。
- 第三个瓶颈:查余票的读放大。 → 破解:多级缓存(余票状态缓存,容忍秒级延迟)。
- 第四个瓶颈:排队系统自身要扛住所有人。 → 破解:等候室本身要做得极简、可大量水平扩。
10. 安全与合规要点
- 🔴 防机器人 / 脚本抢票:验证码、设备指纹、风控、实名 + 限购,对抗黄牛——这是公平性的技术防线。
- 超卖防护:原子扣减是安全问题(超卖 = 卖出不存在的资产)。
- 防刷接口:开售前的探测、刷余票接口都要限流。
- 支付安全:见 支付系统模板。
11. 常见误区 / 反模式
- ❌ 开售让所有人直接打核心系统 → ✅ 虚拟等候室削峰,把洪峰挡在门外。
- ❌ 用「查余量 - 减余量」非原子扣减 → ✅ 原子操作 / 行锁,否则必超卖。
- ❌ 锁座不设超时 → ✅ 超时自动释放,别让票被占死。
- ❌ 热点库存硬塞普通数据库扛写 → ✅ 热点放内存原子扣减,必要时分段。
- ❌ 不防机器人 → ✅ 风控 + 实名 + 限购,守住公平。
12. 演进路线:MVP → 成长期 → 成熟期(不同阶段怎么设置)
| 阶段 | 规模量级 | 怎么设置(具体) | 此时该操心什么 |
|---|---|---|---|
| MVP | 小型活动报名 | 数据库行锁 / 乐观锁扣减库存即可,并发不大不必上重型方案 | 先保证不超卖,别过度设计 |
| 成长期 | 中等抢购 | 热点库存放 内存原子扣减、锁座超时释放、限购、基础防刷、异步下单 | 热点写竞争、超卖、占座释放 |
| 成熟期 | 大麦 / 12306 级 | 虚拟等候室削峰、分段库存、多级缓存查余票、风控反黄牛、全链路异步化 | 峰值承载、公平对抗、稳定性 |
13. 可复用要点
- 💡 「把洪峰挡在门外」比「在门内加机器」更根本。 排队 / 等候室 / 限流,是应对瞬时尖刺流量的第一选择——这和 消息队列削峰 同源。
- 💡 原子操作是防超卖的命根子:任何「争抢有限资源」的场景(秒杀、抢券、抢座),都要用原子扣减,而非「读 - 改 - 写」。
- 💡 「占用 + 超时释放」是处理「临时持有稀缺资源」的通用模式:订座、库存预占、分布式锁,都是它。
- 💡 把超热点数据放内存:让一行数据库去扛百万并发写,是注定的瓶颈;内存级原子操作才扛得住。
🎯 随堂检验
- A狂加服务器硬扛
- B虚拟等候室:把洪峰挡在核心系统门外、按能力放行
- C限制总售票数量
参考原型与延伸阅读
本模板基于以下公开工程资料整理。抢票 / 票务系统的核心难点(虚拟等候室、削峰、座位锁定)在下面几篇里讲得很透。
📖 工程文章 / 方案:
- Queue-it: Virtual Waiting Room — 虚拟等候室的商业方案,FIFO + 随机化排队、按「每分钟放行量」控制出流,防峰值压垮与防刷。
- AWS: 用 Queue-it 虚拟等候室应对峰值流量 — AWS 官方博客,给出虚拟等候室的落地架构(队列状态存储、放行控制)。
- InfoQ: SeatGeek 如何应对高需求开售 — SeatGeek 工程分享,讲票务系统用虚拟等候室处理高需求开售(座位锁定 / 排队 / 限流)。
📌 一句话记住抢票系统:它不是「一个卖票的网站」,而是「极端瞬时洪峰争抢稀缺资源的战场」——所有设计都在回答『怎么同时做到不超卖、不崩、还相对公平』:把洪峰挡在门外、用原子操作守住库存、给占座装上超时。