交易核心系统:支持多键O(1)查询的订单存储数据结构选型咨询
解决方案:双哈希表(双重映射)结构
要同时满足按订单ID和标的名(symbol name)的O(1)查询需求,最直接且高效的方案是维护两个并行的哈希表(Map),分别对应两种查询维度:
1. 双Map的结构定义
- ID到订单的映射:
id_order_map,key为订单唯一ID(int类型),value为对应的Order对象实例。这个Map专门处理场景1(客户端基于ID的修改请求)和场景2(定时器基于ID检查到期),直接通过ID就能O(1)定位到目标订单,完全避免遍历全量数据。 - 标的名到订单集合的映射:
symbol_orders_map,key为标的名(string类型),value为该标的下所有订单的有序集合(保持你原有设计的有序数组即可,满足Tick数据处理的排序需求)。这个Map继续承担场景3的Tick数据匹配工作,保证按标的名快速定位订单列表。
2. 核心操作的同步逻辑
因为两个Map是强关联的,所有订单的增、删、改操作必须原子性地同步更新两个Map,否则会出现数据不一致:
- 新增订单:先将订单插入
id_order_map,再将订单添加到symbol_orders_map对应标的的有序集合中,整个过程加锁保证线程安全。 - 修改订单:如果修改的内容涉及标的名(虽然订单创建后标的名一般不会改,但需考虑极端情况),需要先从原标的的集合中移除订单,更新订单的标的名后,再添加到新标的的集合,同时更新
id_order_map中的订单数据;如果只是修改价格、止盈止损等字段,直接通过id_order_map找到订单修改即可,无需改动symbol_orders_map(除非排序依赖的字段变化,需要重新调整有序集合的位置)。 - 删除订单:先通过
id_order_map找到订单,获取其标的名,然后从symbol_orders_map对应标的的集合中移除该订单,最后删除id_order_map中的条目,全程加锁。
3. 多线程安全的实现要点
系统支持多线程处理时,必须保证双Map的并发读写安全:
- 基础方案:给两个Map加全局互斥锁,所有增删改查操作都需要先获取锁,避免并发冲突。这种方案实现简单,但高并发场景下锁竞争会影响性能。
- 优化方案:使用细粒度锁降低竞争:
- 对
id_order_map可以按ID的哈希值分段,每段对应一个锁,只在操作对应分段的ID时加锁; - 对
symbol_orders_map可以按标的名的哈希值分段,或者直接给每个标的的订单集合单独加锁,这样不同标的的操作可以并行执行,大幅提升并发性能。
- 对
- 也可以直接使用语言自带的线程安全哈希表实现(比如Go的
sync.Map、Java的ConcurrentHashMap、C++的std::shared_mutex配合哈希表),减少手动锁的复杂度。
4. 有序集合的选择
如果Tick数据处理需要订单按价格等字段有序,symbol_orders_map的value可以继续使用有序数组(插入时维护排序),或者换成更高效的有序数据结构(比如红黑树、跳表),平衡插入、删除和遍历的性能。如果不需要严格有序,用普通链表或哈希集合即可进一步降低操作开销。
内容的提问来源于stack exchange,提问作者michael.yue
相关产品推荐
相关产品推荐

