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

在交易撮合中,如何高效处理撤单请求?请设计一个算法,保证撤单的实时性和正确性,并分析其时间复杂度。

上海证券交易所A03 信息技术类难度:中等

答案

1) 【一句话结论】

采用“订单状态标记无效+待撮合队列移除+对手方订单失效通知”的原子操作,通过数据库事务和乐观锁保证实时性、正确性,时间复杂度近似O(1)。

2) 【原理/概念讲解】

在交易撮合系统中,订单状态分为“待撮合”“已成交”“已撤”等。撤单处理的核心逻辑是:先标记订单为“已撤”,再从待撮合队列中移除,并向对手方发送订单失效通知,确保撤单后对手方不再匹配该订单。类比:订单是“待匹配的合约”,撤单相当于“合约作废”,系统不再匹配,同时通知对手方合约作废,避免后续错误匹配。

具体步骤:

  1. 验证订单有效性:检查订单是否存在且状态允许撤单(如未成交);
  2. 事务操作(乐观锁+状态更新+队列移除+日志+对手方通知):更新订单状态为“已撤”,记录撤单时间,从撮合队列删除订单,记录操作日志,并向对手方系统发送订单失效消息;
  3. 返回成功响应。

3) 【对比与适用场景】

方法定义特性使用场景注意点
立即删除撤单时直接物理删除订单记录逻辑简单,但可能导致数据不一致(如日志未同步)低并发、小流量场景事务回滚复杂,恢复困难,对手方无法获知订单失效
标记无效撤单时仅更新订单状态为“已撤”,不删除记录逻辑健壮,支持恢复,数据一致性高高并发、大流量场景(如交易所)需定期清理无效订单,对手方需主动查询状态
标记无效+对手方通知在标记无效基础上,向对手方发送订单失效消息增加对手方匹配逻辑,避免重复匹配高并发、对手方系统依赖订单状态需确保消息可靠传输,避免消息丢失

4) 【示例】

伪代码示例(处理撤单请求,含并发控制与对手方通知)

函数 handle_cancel(order_id, user_id):
    1. 验证订单有效性:
       SELECT * FROM orders WHERE order_id = order_id AND user_id = user_id AND status IN ('待撮合', '未成交');
       若不存在或状态为“已成交”,返回错误。
    2. 事务操作(乐观锁+状态更新+队列移除+日志+对手方通知):
       START TRANSACTION;
       -- 乐观锁:检查版本号
       SELECT version FROM orders WHERE order_id = order_id FOR UPDATE;
       UPDATE orders SET status = '已撤', cancel_time = now(), version = version + 1 WHERE order_id = order_id AND user_id = user_id AND version = version;
       -- 从队列移除
       DELETE FROM matching_queue WHERE order_id = order_id;
       -- 记录日志
       INSERT INTO order_log (order_id, user_id, action, time) VALUES (order_id, user_id, '撤单', now());
       -- 通知对手方订单失效
       SEND_MESSAGE TO opponent_system (order_id, 'order_invalid', now());
       COMMIT;
    3. 返回成功响应。

撤单请求示例(JSON)

{
  "order_id": "ORD12345",
  "user_id": "U001",
  "timestamp": "2024-01-15T10:30:00Z"
}

5) 【面试口播版答案】

“面试官您好,处理撤单请求时,核心是采用‘状态标记+队列移除+对手方通知’的原子流程。具体来说,收到撤单请求后,先验证订单存在且状态允许撤单(如未成交),然后通过事务更新订单状态为‘已撤’,从待撮合队列删除,并记录日志。同时,向对手方订单的匹配系统发送失效通知,确保对手方不再匹配。这样既保证了撤单的实时性,又避免了对手方订单的重复匹配错误。时间复杂度上,状态更新和队列移除都是O(1)操作,整体复杂度近似O(1),适合高并发交易场景。”

6) 【追问清单】

  1. 并发撤单处理:多个用户同时撤同一个订单怎么办?
    • 回答要点:采用乐观锁(版本号),通过数据库的行级锁保证并发安全,避免数据冲突。
  2. 事务原子性:如果更新状态和移除队列同时失败,如何保证一致性?
    • 回答要点:使用数据库事务,将状态更新、队列移除、日志记录和对手方通知放在同一个事务中,确保原子性,失败则回滚。
  3. 对手方订单重新匹配:撤单后对手方订单如何处理?
    • 回答要点:对手方系统通过订阅消息(如Kafka)获取订单失效通知,重新计算匹配结果,避免重复撮合。
  4. 批量撤单优化:用户一次性撤多个订单时如何优化?
    • 回答要点:批量操作时,先检查订单状态,然后批量更新状态并从队列移除,减少数据库操作次数,提高效率。
  5. 系统恢复:历史中的无效订单如何清理?
    • 回答要点:定期(如每天)清理状态为“已撤”且超时一定时间(如24小时)的订单,避免数据膨胀,影响系统性能。

7) 【常见坑/雷区】

  1. 直接物理删除订单:可能导致数据不一致(如日志未同步),对手方无法获知订单已撤,引发匹配错误。
  2. 忽略对手方重新匹配:撤单后对手方订单继续匹配,导致错误成交或重复撮合。
  3. 事务未回滚:若更新状态失败,订单可能处于“部分撤单”状态,引发逻辑错误,如订单仍被撮合。
  4. 并发锁冲突:乐观锁版本号不一致时,导致更新失败,需要重试,影响实时性。
  5. 消息丢失:对手方通知消息丢失,导致对手方仍匹配已撤订单,需保证消息队列可靠性(如Kafka的持久化)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1