以下是整理好的 Markdown 格式文档,涵盖了从用户下单到支付/取消的全链路技术实现细节。
购票系统核心业务流程架构
本项目通过 Redis Lua 脚本、Kafka 消息队列、延迟队列 和 分布式锁 等技术,实现了从用户选座、下单、支付到取消的高并发业务闭环。
1. 订单创建流程(异步高性能模式)
为了应对高并发抢票场景,系统采用了异步下单架构,将“预扣库存”和“实际落库”分离,确保前端极致响应。
1.1 预扣库存(Redis + Lua)
- 核心逻辑:用户提交订单请求后,首先在 Redis 中进行操作,不直接访问数据库。
- 代码位置:
damai-program-service->ProgramOrderService.createOrderOperateProgramCacheResolution - 技术亮点:使用 Lua 脚本 保证多步操作的原子性,防止超卖:
- 检查余票:验证票档余票是否充足。
- 检查座位:验证选定座位状态是否为
NO_SOLD(未售)。 - 扣减库存:扣减对应票档的余票数量。
- 锁定座位:将座位状态更新为
LOCK(锁定),并存入 Redis Hash 结构。
1.2 异步削峰(Kafka)
- 核心逻辑:预扣库存成功后,组装订单数据对象 (
OrderCreateMq),发送消息到 Kafka。 - 代码位置:
damai-program-service->ProgramOrderService.doCreateV2 - Topic:
create_order - 技术亮点:利用 Kafka 实现流量削峰与服务解耦,让前端快速得到“下单中”的响应,无需等待数据库操作完成。
1.3 订单落库(消费者处理)
- 核心逻辑:订单服务监听 Kafka 消息并写入 MySQL。
- 代码位置:
damai-order-service->CreateOrderConsumer - 处理细节:
- 延迟检查:收到消息后,检查消息积压时间(如是否超过 5秒)。若积压严重,为保证用户体验,可能直接丢弃消息并记录为
DISCARD_ORDER(用户端显示下单失败),防止用户长时间等待。 - 事务落库:调用
OrderService.createMq,在 MySQL 中原子性插入订单主表、购票人订单表和订单节目关联表。
- 延迟检查:收到消息后,检查消息积压时间(如是否超过 5秒)。若积压严重,为保证用户体验,可能直接丢弃消息并记录为
1.4 发送延迟取消消息
- 核心逻辑:在发送创建订单消息的同时,并行发送一条延迟消息。
- Topic:
delay_order_cancel - 延迟时间:通常为 15-30 分钟。
- 目的:用于“超时未支付”场景的兜底处理,确保订单超时自动取消。
2. 订单取消流程(主动取消 & 超时取消)
无论是用户主动点击取消,还是延迟队列触发的超时取消,最终都汇聚到统一的取消逻辑,确保数据一致性。
2.1 触发机制
- 超时触发:
damai-order-service的DelayOrderCancelConsumer监听到延迟消息。 - 主动触发:用户调用 API 接口。
2.2 状态更新与幂等性
- 代码位置:
damai-order-service->OrderService.cancel - 技术亮点:
- 分布式锁:使用
@ServiceLock(基于 Redisson) 锁定订单号,防止并发操作(如用户在超时的毫秒级瞬间完成支付)。 - 幂等性检查:判断订单状态,若已是
CANCEL或PAY,则直接返回,避免重复处理。 - 数据库事务:更新 MySQL 中订单状态为
CANCEL。
- 分布式锁:使用
2.3 库存回滚(Redis Lua)
- 核心逻辑:订单取消后,必须释放被锁定的座位和库存,供其他用户购买。
- 代码位置:
damai-order-service->OrderService.updateProgramRelatedDataResolution - 技术亮点:使用 Lua 脚本 (
programCacheReverseOperate) 反向操作 Redis:- 释放座位:将座位从“锁定”列表移除,加回“未售”列表。
- 回补库存:增加对应票档的余票数量。
- 数据同步:(V4版本优化) 通过 RPC 调用
programClient异步或同步更新数据库中的座位状态。
3. 支付成功流程
3.1 支付回调
- 触发:支付宝/微信服务端回调
OrderService.alipayNotify。
3.2 状态确认
- 并发控制:加分布式锁,防止回调重试导致的重复处理。
- 状态更新:将 MySQL 订单状态更新为
PAY。
3.3 最终一致性
- Redis 状态变更:使用 Lua 脚本将 Redis 中的座位状态从
LOCK改为SOLD(已售)。 - 数据库最终一致:发送延迟消息
delay_operate_program_data给节目服务,异步将 MySQL 中的座位数据最终更新为“已售”。
4. 业务流程架构图
mermaid
graph TD
User[用户] -->|1. 选座下单| ProgramService[节目服务]
subgraph 预下单阶段
ProgramService -->|2. Lua脚本预扣库存/锁座| Redis[(Redis缓存)]
ProgramService -->|3. 发送创建订单消息| Kafka{Kafka消息队列}
ProgramService -->|4. 发送延迟取消消息| DelayQueue{延迟队列}
end
subgraph 订单落库阶段
Kafka -->|5. 消费消息| OrderService[订单服务]
OrderService -->|6. 订单落库| MySQL[(MySQL)]
end
subgraph 取消/回滚阶段
DelayQueue -->|7a. 超时未支付| OrderService
User -->|7b. 主动取消| OrderService
OrderService -->|8. 更新订单状态为CANCEL| MySQL
OrderService -->|9. Lua脚本回滚库存/解锁| Redis
end
subgraph 支付阶段
User -->|10. 支付成功回调| OrderService
OrderService -->|11. 更新状态为PAY| MySQL
OrderService -->|12. Lua脚本置为已售| Redis
end