交易系统技术专家高阶面试宝典 - 第3节
第3章 订单系统核心面试题:撮合引擎、订单状态机、防重设计、高并发处理
本章知识结构
| 核心能力域 | 技术深度要求 | 常见考察方式 | 高频考点 |
|---|---|---|---|
| 撮合引擎 | 内存撮合 vs 持久化撮合、价格-时间优先、锁机制 | 方案设计 + 场景推演 | 撮合算法、并发冲突、延迟优化 |
| 订单状态机 | 有限状态机、生命周期、补偿&回滚 | 状态机图 + 异常处理 | 状态定义、幂等、超时处理 |
| 防重设计 | 幂等性、去重表、分布式锁、唯一键 | 方案对比 + 代码级设计 | 重复下单、重复支付、消息重复消费 |
| 高并发处理 | 缓存、异步、分库分表、限流降级 | 系统架构 + 压测数据 | 库存扣减、热点账户、写瓶颈 |
面试问答卡片
🎯 面试问题:设计一个交易系统的订单撮合引擎,如何保证高性能和公平性?
🎯 面试官考察点: 撮合算法选择、锁竞争优化、内存与持久化一致性、对价格-时间优先原则的理解。
📌 回答框架: ① 坚持价格优先、时间优先核心原则;② 内存维护买卖订单队列(红黑树/跳表)+ 异步持久化;③ 分段锁或CAS减少锁冲突;④ 定时批量落盘保证重启恢复。
✍️ 简短示例回答: 采用价格-时间优先算法,买方向价格从高到低、时间从早到晚排序。买卖队列放内存并用读写锁控制并发,每秒批量刷盘一次。买方撤单时通过订单ID直接移除队列节点,避免全表扫描。单机QPS达到5万+。
🔍 可能追问: 若多只股票共用一个撮合线程如何优化?如何防止内存数据丢失?
🎯 面试问题:设计订单状态机,请描述核心状态流转以及异常处理方案。
🎯 面试官考察点: 状态机设计是否完整、异常状态处理(超时/支付失败/库存不足)、事务边界、可观测性。
📌 回答框架: ① 定义有限状态(待支付→已支付→已发货→已完成/已取消);② 使用状态模式或状态表驱动;③ 每个状态变更加版本号乐观锁;④ 超时订单用定时任务+消息队列补偿。
✍️ 简短示例回答: 采用状态表驱动,核心状态:INIT→PAID→SHIPPED→DONE,以及CANCELED。每次状态变更前校验前序状态,使用乐观锁+版本号防止并发。超时未支付由延迟队列触发关闭并释放库存。
🔍 可能追问: 支付成功后调用订单状态更新失败怎么办?同一个订单同时请求支付成功和取消怎么处理?
🎯 面试问题:高并发下单场景如何防止重复下单和重复支付?
🎯 面试官考察点: 幂等设计能力、分布式锁选型、缓存与DB一致性、抗流量能力。
📌 回答框架: ① 前端按钮置灰+请求唯一ID;② 后端用防重表(唯一索引)+ Redis分布式锁;③ 数据库层面使用乐观锁(版本号);④ 支付回调需做幂等,使用支付流水号去重。
✍️ 简短示例回答: 每个请求带,后端用Redis set nx防重,超时30秒。订单创建使用数据库唯一键(用户ID+商品ID+请求时间戳)。支付回调按支付单号去重,先查再插。
🔍 可能追问: 如果Redis挂了如何处理?重复消息到达消息队列如何保证恰好一次?
项目案例:高并发交易平台订单系统重构
| 项目名称 | 千亿级股票交易平台订单系统V3.0重构 |
| 业务背景 | 原系统使用MySQL行锁撮合,QPS仅3000,随着行情火爆订单量暴增10倍,出现频繁死锁和订单丢失。需要重构成内存撮合+异步持久化。 |
| 规模指标 | 日撮合订单数5000万+;峰值QPS 12万;撮合延迟 <2ms (P99);订单状态变更延迟 <50ms。 |
| 技术栈 | Java 17 + Netty + 内存红黑树 + Redis + RocketMQ + MySQL 8.0 + sharding-jdbc |
| 核心难点 | ① 内存撮合一致性:宕机恢复10秒内重建队列;② 热点股票单请求冲突:引入分段锁+无锁CAS;③ 订单状态机高并发:乐观锁+版本号防止覆盖;④ 防重:支付回调与内部状态更新幂等。 |
| 面试高频追问 |
|
| 可迁移回答话术 | 「我们采用内存撮合+异步持久化,每次撮合后记录WAL日志,重启时通过WAL回放重建队列。热点股票使用分段锁,将买卖队列按价格区间分成多段,减少锁竞争。状态更新使用乐观锁版本号,版本不一致时重试。支付回调幂等通过业务流水号唯一索引实现。」 |