Skip to content

以下是整理好的 Markdown 格式文档,涵盖了从用户下单到支付/取消的全链路技术实现细节。


购票系统核心业务流程架构

本项目通过 Redis Lua 脚本Kafka 消息队列延迟队列分布式锁 等技术,实现了从用户选座、下单、支付到取消的高并发业务闭环。

1. 订单创建流程(异步高性能模式)

为了应对高并发抢票场景,系统采用了异步下单架构,将“预扣库存”和“实际落库”分离,确保前端极致响应。

1.1 预扣库存(Redis + Lua)

  • 核心逻辑:用户提交订单请求后,首先在 Redis 中进行操作,不直接访问数据库。
  • 代码位置damai-program-service -> ProgramOrderService.createOrderOperateProgramCacheResolution
  • 技术亮点:使用 Lua 脚本 保证多步操作的原子性,防止超卖:
    1. 检查余票:验证票档余票是否充足。
    2. 检查座位:验证选定座位状态是否为 NO_SOLD(未售)。
    3. 扣减库存:扣减对应票档的余票数量。
    4. 锁定座位:将座位状态更新为 LOCK(锁定),并存入 Redis Hash 结构。

1.2 异步削峰(Kafka)

  • 核心逻辑:预扣库存成功后,组装订单数据对象 (OrderCreateMq),发送消息到 Kafka。
  • 代码位置damai-program-service -> ProgramOrderService.doCreateV2
  • Topiccreate_order
  • 技术亮点:利用 Kafka 实现流量削峰与服务解耦,让前端快速得到“下单中”的响应,无需等待数据库操作完成。

1.3 订单落库(消费者处理)

  • 核心逻辑:订单服务监听 Kafka 消息并写入 MySQL。
  • 代码位置damai-order-service -> CreateOrderConsumer
  • 处理细节
    • 延迟检查:收到消息后,检查消息积压时间(如是否超过 5秒)。若积压严重,为保证用户体验,可能直接丢弃消息并记录为 DISCARD_ORDER(用户端显示下单失败),防止用户长时间等待。
    • 事务落库:调用 OrderService.createMq,在 MySQL 中原子性插入订单主表、购票人订单表和订单节目关联表。

1.4 发送延迟取消消息

  • 核心逻辑:在发送创建订单消息的同时,并行发送一条延迟消息。
  • Topicdelay_order_cancel
  • 延迟时间:通常为 15-30 分钟。
  • 目的:用于“超时未支付”场景的兜底处理,确保订单超时自动取消。

2. 订单取消流程(主动取消 & 超时取消)

无论是用户主动点击取消,还是延迟队列触发的超时取消,最终都汇聚到统一的取消逻辑,确保数据一致性。

2.1 触发机制

  • 超时触发damai-order-serviceDelayOrderCancelConsumer 监听到延迟消息。
  • 主动触发:用户调用 API 接口。

2.2 状态更新与幂等性

  • 代码位置damai-order-service -> OrderService.cancel
  • 技术亮点
    • 分布式锁:使用 @ServiceLock (基于 Redisson) 锁定订单号,防止并发操作(如用户在超时的毫秒级瞬间完成支付)。
    • 幂等性检查:判断订单状态,若已是 CANCELPAY,则直接返回,避免重复处理。
    • 数据库事务:更新 MySQL 中订单状态为 CANCEL

2.3 库存回滚(Redis Lua)

  • 核心逻辑:订单取消后,必须释放被锁定的座位和库存,供其他用户购买。
  • 代码位置damai-order-service -> OrderService.updateProgramRelatedDataResolution
  • 技术亮点:使用 Lua 脚本 (programCacheReverseOperate) 反向操作 Redis:
    1. 释放座位:将座位从“锁定”列表移除,加回“未售”列表。
    2. 回补库存:增加对应票档的余票数量。
  • 数据同步:(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