51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

请设计一个支持百万级并发订单的股票交易撮合系统,需要考虑高并发、低延迟、容错性,请描述系统的主要组件、数据流和关键技术选型。

上海证券交易所A04 金融经济类难度:困难

答案

1) 【一句话结论】

采用分布式订单簿(Redis有序集合)+ 消息队列(Kafka)+ 多级缓存架构,通过事务/消息确认保证数据一致性,分片+过期清理控制内存,实现百万级并发下的低延迟、高可用及容错性。

2) 【原理/概念讲解】

股票交易撮合系统的核心是“订单簿”与“撮合引擎”。订单簿分为买方队列(按价格降序、时间升序排列)和卖方队列(按价格升序、时间升序排列),用于实时匹配买卖订单。撮合引擎按“价格优先、时间优先”规则匹配:当买方队列最低价≥卖方队列最高价时,触发成交。系统组件包括:订单接收层(处理请求、验证参数)、订单簿管理(Redis存储买方/卖方队列)、消息队列(Kafka处理订单流)、持久化存储(MySQL存储历史数据)、监控告警(实时监控延迟、错误率)。订单簿的有序集合结构类似数据库的索引,但支持实时更新和查询,好比超市货架的动态排位,买方按“高价优先”排,卖方按“低价优先”排,收银员(撮合引擎)按规则快速匹配,完成交易。同时,订单状态管理(未成交、已成交、已撤单)通过Redis的zrem操作实现,确保撤单时能及时更新订单簿。

3) 【对比与适用场景】

对比项Redis(有序集合)MySQL(InnoDB)Kafka(消息队列)RabbitMQ(队列)
定义内存数据库,支持有序集合(zset),用于实时存储订单簿关系型数据库,事务支持,用于持久化历史数据分布式消息队列,用于订单流传输基于消息队列,用于小流量精确投递
读写性能毫秒级读写(内存访问)磁盘I/O,秒级(复杂查询慢)低延迟(批量处理,毫秒级)中(单条处理,微秒级)
数据持久化RDB/AOF(可选,保证数据不丢失)InnoDB事务,持久化到磁盘持久化日志(高可靠,保留策略)镜像队列(可靠投递,但延迟高)
适用场景订单簿(实时查询、更新)历史订单、用户信息、交易记录订单流(大流量、顺序处理)小流量、精确投递(如通知)
注意点内存占用大,需分片/过期清理事务支持,复杂查询慢;读写分离分区导致消息乱序;需设置重试机制队列模式复杂,延迟高;消息持久化不足
选择依据:Redis有序集合适合实时匹配(低延迟),Kafka适合高吞吐订单流(分区实现负载均衡),MySQL用于持久化历史数据(事务保证一致性)。

4) 【示例】

订单提交与撤单处理(伪代码)

# 订单提交接口(含状态管理)
def submit_order(order_id, user_id, stock_code, price, quantity, order_type):
    if not validate_order(user_id, stock_code, quantity):
        return {"code": "invalid", "msg": "参数错误"}
    # 1. 更新订单簿(事务保证原子性)
    with redis.pipeline() as pipe:
        pipe.zadd(f"buy-{stock_code}", {order_id: price}, order_type)  # 买方队列
        pipe.zadd(f"sell-{stock_code}", {order_id: price}, order_type)  # 卖方队列
        pipe.execute()
    # 2. 发送订单消息
    kafka_producer.send(topic="order-stream", key=stock_code, value=order_json)
    return {"code": "success", "msg": "订单提交成功"}

# 订单撤单接口(仅未成交订单可撤单)
def cancel_order(order_id, stock_code):
    order_status = redis.hget(f"order-{order_id}", "status")
    if order_status == "unmatched":
        with redis.pipeline() as pipe:
            pipe.zrem(f"buy-{stock_code}", order_id)  # 删除买方订单
            pipe.zrem(f"sell-{stock_code}", order_id)  # 删除卖方订单
            pipe.hset(f"order-{order_id}", "status", "canceled")
            pipe.execute()
        kafka_producer.send(topic="cancel-stream", value=cancel_json)
        return {"code": "success", "msg": "撤单成功"}
    else:
        return {"code": "failed", "msg": "订单已成交,无法撤单"}

# 撮合引擎(批量操作优化)
def match_orders():
    while True:
        orders = kafka_consumer.poll(timeout=100)  # 批量消费
        for order in orders.values():
            order_data = json.loads(order.value)
            stock_code = order_data["stock_code"]
            # 获取订单簿(批量查询)
            buy_queue = redis.zrange(f"buy-{stock_code}", 0, -1, withscores=True)
            sell_queue = redis.zrange(f"sell-{stock_code}", 0, -1, withscores=True)
            if buy_queue and sell_queue:
                buy_price, _ = buy_queue[-1]
                sell_price, _ = sell_queue[0]
                if buy_price >= sell_price:
                    execute_trade(order_data)  # 执行成交
                    # 批量更新订单簿(事务)
                    with redis.pipeline() as pipe:
                        pipe.zrem(f"buy-{stock_code}", buy_price)  # 删除买方订单
                        pipe.zrem(f"sell-{stock_code}", sell_price)  # 删除卖方订单
                        pipe.execute()
                    kafka_producer.send(topic="trade-result", value=trade_json, 
                                       callback=lambda m: log.info("成交消息已确认"))

5) 【面试口播版答案】

面试官您好,设计百万级并发股票交易撮合系统,核心是构建分布式订单簿(用Redis有序集合存储买方/卖方队列),通过消息队列(Kafka)处理订单流,确保低延迟。订单接收层将订单发送到Kafka,撮合引擎消费订单后,实时更新Redis中的订单簿。当买方队列最低价≥卖方队列最高价时,触发成交,并通过Redis事务保证订单簿更新与消息发送的原子性,避免数据不一致。关键技术包括Redis的有序集合实现实时匹配,Kafka保证消息持久化与顺序,按股票代码分片控制内存,定期清理过期订单,避免OOM。系统还设计了主从复制、故障转移,确保高可用,监控延迟和错误率,实现百万级并发下的低延迟、高可用及容错性。

6) 【追问清单】

  • 问:如何处理订单撤单?
    答:订单状态管理(如未成交订单可撤单),通过Redis事务删除订单簿中的订单,并更新订单状态为“已撤单”,同时发送撤单消息。

  • 问:系统如何应对网络分区?
    答:消息持久化(Kafka日志保留策略),订单簿数据复制(Redis主从),故障转移(主从切换,切换时间<1秒)。

  • 问:内存监控与自动扩容?
    答:设置Redis内存阈值,当内存占用超过阈值时,触发扩容(如增加Redis实例分片,或清理过期订单),避免OOM。

  • 问:消息队列分区策略?
    答:按股票代码分区,每个分区对应一个Kafka分区,消费者组按分区消费,实现负载均衡,避免单分区过载。

  • 问:如何避免消息乱序导致撮合错误?
    答:Kafka按分区顺序消费,结合Redis有序集合(zset)保证价格优先,确保订单按时间顺序处理,避免乱序撮合。

7) 【常见坑/雷区】

  • 坑1:数据不一致(订单簿更新与消息发送不同步,导致重复或遗漏)。
  • 坑2:内存溢出(未分片或过期清理,Redis存储过多订单,OOM)。
  • 坑3:消息持久化不足(Kafka未开启持久化,订单丢失后无补偿)。
  • 坑4:消息乱序(Kafka分区导致消息乱序,未正确处理导致价格优先失效)。
  • 坑5:未考虑限流/熔断(高并发时系统崩溃,未设置流量控制)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1