
高并发证券交易撮合系统需采用分布式分层架构,以订单状态机为核心,通过多级缓存+消息队列解耦,分库分表存储,结合最终一致性策略,确保万级TPS与毫秒级响应。
系统分为接入层、匹配层、存储层、监控层四层:
订单状态机像业务流程的“交通灯”,每个状态转换有明确规则(如校验通过后状态变为“已校验”),确保业务逻辑完整性。
| 技术组件 | Redis | Memcached | 适用场景 | 注意点 |
|---|---|---|---|---|
| 定义 | 内存数据库,支持持久化、事务、发布订阅 | 纯内存缓存,无持久化 | 接入层限流、匹配层订单缓存、热点数据预热 | Redis需配置RDB(每分钟备份)和AOF(每秒追加),避免数据丢失;Memcached需定期手动备份,否则重启会丢失数据 |
| 特性 | 高并发读写,数据持久化,支持复杂操作 | 低延迟,简单缓存,无持久化 | 限流、订单缓存、会话 | Redis事务(MULTI/EXEC)保证多操作原子性,Memcached仅缓存,无事务 |
| 技术组件 | Kafka | RabbitMQ | 适用场景 | 注意点 |
|---|---|---|---|---|
| 定义 | 分布式消息队列,高吞吐、持久化 | 企业级消息队列,轻量、支持多种协议 | 订单流(高吞吐,如每秒10万条)、日志、匹配后订单确认 | Kafka需管理分区(按股票代码分区,保证消息顺序),RabbitMQ需设置消息持久化(delivery mode=2),确保消息不丢失 |
| 特性 | 高吞吐,持久化,分区复制 | 轻量,支持工作流,消息确认 | 订单流处理、异步通知 | Kafka需消费者组管理,RabbitMQ需交换机(如topic交换机)和队列绑定 |
| 技术组件 | 分布式数据库(如TiDB) | 单体数据库(如MySQL) | 适用场景 | 注意点 |
|---|---|---|---|---|
| 定义 | 分布式架构,支持分库分表,分布式事务 | 单机或集群,垂直扩展 | 订单、成交、持仓等核心数据 | TiDB支持高并发读写(如百万级TPS),分库分表(按股票代码分表,按时间维度分库),分布式事务(两阶段提交,保证数据一致性);MySQL需主从复制,扩展性差 |
| 特性 | 高并发,分库分表,分布式事务 | 高并发,垂直扩展,事务 | 核心业务数据 | TiDB需设计分片键(如stock_code作为分片键),避免热点数据集中;MySQL需主从同步,延迟可能较高 |
| 当前状态 | 触发操作 | 下一个状态 |
|---|---|---|
| 已提交 | 校验通过 | 已校验 |
| 已校验 | 加入撮合 | 待撮合 |
| 待撮合 | 撮合成功 | 已撮合 |
| 已撮合 | 更新持仓 | 已成交 |
| 已成交 | 用户撤单 | 已撤单 |
def match_orders(bids, asks):
bids.sort(key=lambda x: x['price'], reverse=True) # 买方价格高优先
asks.sort(key=lambda x: x['price']) # 卖方价格低优先
matched = []
while bids and asks:
bid = bids[0]
ask = asks[0]
if bid['price'] >= ask['price']:
quantity = min(bid['quantity'], ask['quantity'])
matched.append({
"order_id": bid['order_id'],
"stock_code": bid['stock_code'],
"price": ask['price'],
"quantity": quantity,
"type": "buy"
})
bid['quantity'] -= quantity
ask['quantity'] -= quantity
if bid['quantity'] == 0:
bids.pop(0)
if ask['quantity'] == 0:
asks.pop(0)
else:
break
return matched
冷启动时,定时任务(如每分钟)从数据库预加载前10个热门股票的订单数据(按成交量排序),存入Redis有序集合(key为“hot_orders”,按价格排序),减少后续请求的数据库压力。热点数据更新策略:当订单量超过阈值(如每秒1000条)时,动态更新缓存中的热点数据,确保缓存数据时效性。
面试官好,我设计的系统核心是分布式分层架构,分接入、匹配、存储三层。接入层用API网关处理订单请求,校验用户身份和参数(如用户认证、订单参数有效性);匹配层通过订单状态机管理订单流转(如已提交→已校验→待撮合→已成交),生成消息推送到Kafka,再由消费端更新数据库。缓存用Redis缓存订单和成交记录,减少数据库压力;数据库分库分表(按股票代码分表,按时间维度分库),提升读写性能。数据一致性采用最终一致性,消息队列确保消息不丢失,数据库事务保证核心数据(如持仓)一致性。系统稳定性方面,接入层有熔断,匹配层降级,数据库主从复制,监控指标实时采集,故障自动切换。比如通过压测,系统在10万并发下延迟小于5ms,支持万级TPS。订单状态机通过Redis的SETNX实现分布式锁,确保状态转换原子性,避免并发下的数据不一致。缓存预热冷启动时预加载热门股票订单,减少缓存穿透。分库分表按股票代码分表,时间分库,避免热点数据集中。消息队列Kafka处理订单流,RabbitMQ处理状态变更,确保消息可靠。这样能支持万级TPS,毫秒级响应。
问题:订单状态管理如何保证数据一致性?
回答:通过订单状态机,每个状态转换有明确规则(如校验通过后状态变为“已校验”),结合Redis的SETNX实现分布式锁,确保状态转换的原子性,避免并发下的数据不一致。
问题:缓存预热如何实现?
回答:冷启动时预加载热门股票的订单数据(如前10个热门股票的订单),存入Redis有序集合;定期(如每分钟)更新热点数据,减少缓存穿透和击穿。
问题:分库分表的键如何设计?
回答:按股票代码分表(如每个股票一个表),按时间维度分库(如按年/月分库),结合时间戳分片,避免热点数据集中,提升读写性能。
问题:消息队列如何保证消息不丢失?
回答:Kafka采用持久化存储(日志文件),RabbitMQ设置消息持久化(delivery mode=2),结合消费端确认机制(acknowledgment),确保消息可靠传输。
问题:系统如何处理订单超时或网络异常?
回答:接入层设置超时重试,匹配层将异常订单放入重试队列,数据库回滚未完成事务,避免数据不一致。