+
18
-

回答

构建一个类似 12306 高并发订票系统(高铁票务系统)是非常具有挑战性的场景:瞬时流量极高(如春运/节假日放票时每秒数十万请求)、数据一致性要求强(不能超卖)、响应延迟敏感。在这种场景下,单纯依赖传统架构很难扛住压力,而 阿里云的 Serverless + 事件驱动架构 可以作为核心组件,结合精心设计,构建高并发、弹性、可靠的系统。

目标:用阿里云构建一个类似 12306 的订票系统核心链路

注意:12306 官方系统极其复杂,本文聚焦于 “查余票 → 锁座 → 下单 → 支付” 的核心高并发路径,用阿里云组件实现弹性、防超卖、高可用

一、整体架构设计(高并发订票核心链路)

[用户前端] 
   ↓(查余票 / 下单)
[API 网关] 
   ↓
[函数计算 FC] ←→ [Redis(缓存 + 分布式锁)]
   ↓(下单事件)
[EventBridge] → [RocketMQ](削峰 + 解耦)
   ↓(异步消费)
[FC / ECS Worker] → [PolarDB(分布式数据库)]
                        ↑
                   [Redis 预加载余票]

关键点:热点数据缓存 + 库存预热 + 异步落库 + 分布式锁 + 限流熔断

二、核心模块详解

1. 余票查询:全走 Redis(禁止查 DB)

数据预热

票务系统在放票前,将车次、座位、余票等数据提前加载到 Redis(集群版)

使用 Hash 结构 存储:train:G101:date:20251207 → { seat_001: 1, seat_002: 0, ... }(1=可售,0=已锁/售出)

查询逻辑

用户查票 → 直接查 Redis,不经过 DB

Redis 设置 TTL + 主从 + 持久化 保证可用性。

优势:Redis QPS 可达 10w+,轻松应对查票高峰。

2. 下单流程:FC + Redis 分布式锁 + 消息队列

步骤 1:用户点击“下单”

请求 → API 网关函数计算 FC(下单函数)

步骤 2:FC 函数执行(关键!)
# 伪代码
def handle_order(event):
    train_id = event['train']
    seat_id = event['seat']
    user_id = event['user']
    key = f"lock:{train_id}:{seat_id}"

    # 1. Redis 分布式锁(防并发超卖)
    if redis.set(key, user_id, nx=True, ex=30):  # 30秒超时
        # 2. 检查余票(再校验一次)
        if redis.hget(f"train:{train_id}", seat_id) == "1":
            # 3. 锁定座位(标记为“已锁定”)
            redis.hset(f"train:{train_id}", seat_id, "2")  # 2 = locked

            # 4. 发送下单事件到 EventBridge → RocketMQ
            event_bridge.put_events([{
                'source': 'ticket.order',
                'detail': {'train': train_id, 'seat': seat_id, 'user': user_id}
            }])

            return {"code": 200, "msg": "锁座成功,请30分钟内支付"}
        else:
            return {"code": 400, "msg": "座位已被抢"}
    else:
        return {"code": 429, "msg": "手慢了,座位已被锁定"}

关键点

分布式锁 + 原子性检查 是防超卖的核心。

锁有效期 30 分钟(匹配支付超时时间)。

绝不直接写 DB,只操作 Redis。

3. 事件驱动 & 异步落库

EventBridge 接收 FC 发出的订单事件,转发到 RocketMQ

RocketMQ 作用

削峰:放票瞬间百万请求,MQ 缓冲。

解耦:FC 不关心 DB 写入,只负责快速锁座。

保证最终一致性。

消费端(Worker):

可用 FC(轻量)ECS 弹性伸缩组(重任务) 消费 MQ。

消费逻辑:

def consume_order(msg):
    # 1. 写入订单到 PolarDB(主库)
    db.insert_order(...)
    # 2. 更新座位状态为“已售”(可选,因 Redis 已锁定)
    # 3. 如果支付超时未完成,后续由定时任务释放座位

4. 数据库:PolarDB(分布式版)

使用 PolarDB MySQL 兼容版(分布式)

自动读写分离 + 分库分表(按车次/日期分片)。

高并发写入订单、用户、支付记录。

注意:DB 只存储 已支付/最终状态不参与实时库存扣减

5. 缓存与一致性保障

Redis 是唯一库存源(Single Source of Truth for Inventory)。

库存回源机制

若 Redis 宕机,可从 DB 恢复快照(但性能下降,需避免)。

缓存一致性

所有库存变更 只通过 FC + Redis 原子操作

DB 仅作为持久化备份,不反向更新 Redis

6. 高并发防护策略

超卖Redis 分布式锁 + 原子 check-and-set
热点 Key(如热门车次)Redis Cluster 分片 + 本地缓存(如 FC 内存缓存)
FC 冷启动延迟配置 预留实例(Provisioned Concurrency)
MQ 积压自动扩容 Consumer(ECS Auto Scaling)
恶意刷单API 网关限流(QPS/用户/IP) + 验证码
支付超时未释放座位定时任务(FC + EventBridge 定时触发)扫描 Redis,释放超时锁

三、放票流程(库存预热)

T-1 日:运营配置放票计划。

放票前 1 小时

启动 预热 FC 函数,从 DB 读取车次座位信息。

批量写入 Redis:HSET train:G101:20251207 seat_001 1 ...

放票时刻:用户可直接查询 Redis,0 延迟。

四、为什么这个架构能扛住高并发?

OSS存储静态资源(车次图、用户头像等),减轻后端压力
FC无服务器,自动扩缩容,按毫秒计费,适合突发流量
Redis内存操作,10w+ QPS,分布式锁防超卖
RocketMQ异步解耦,削峰填谷,保证不丢单
PolarDB高可用、强一致、自动扩缩容,持久化保障
EventBridge统一事件中枢,连接 FC/MQ/定时任务

核心思想“库存操作在 Redis,落库走异步,查询全缓存,写入靠消息”

五、局限性与补充

强一致性要求:12306 实际使用 内存数据库 + 自研中间件,阿里云方案在极端场景下可能有毫秒级不一致(但业务可接受,因锁座已防超卖)。

复杂查询:如“中转联程票”,需引入 ElasticsearchAnalyticDB

支付回调:支付成功后,需通过 EventBridge 触发“确认订单”流程,更新 Redis 座位为“已售”。

灾备:Redis 开启 跨可用区部署,PolarDB 开启 全球数据库(GDN)

六、总结

用阿里云打造 12306 级订票系统,关键是:

库存前置到 Redis(唯一真实库存)

FC 原子锁座(防超卖)

MQ 异步落库(削峰解耦)

全链路 Serverless(弹性 + 低成本)

严格限流 + 熔断(保护系统不崩)

虽然无法 100% 复刻 12306,但该架构已能支撑 百万级 QPS 的订票核心链路,且具备自动弹性、高可用、低成本优势,非常适合互联网票务、秒杀、抢购等场景。

网友回复

我知道答案,我要回答