一、撮合队列基础:从排队说起
大家好,我是老张。今天咱们聊聊撮合队列。
先问个问题:你去银行办业务,是不是得取号排队?前面的人办完了,才轮到你。这个「排队」的过程,其实就是队列的核心思想。
金融交易系统里的撮合队列,说白了就是给买卖订单排队的机制。只不过这个队伍排得特别快——毫秒级别,而且规则极其严格。
什么是撮合队列
撮合队列,是交易引擎用来管理订单的核心数据结构。它负责接收买卖双方的订单,按照价格优先、时间优先的原则进行匹配。
我打个比方:
- 买方说「我出10块钱买1股」
- 卖方说「我9块9卖1股」
- 撮合队列一看:买方出价高于卖方要价,成交!
就这么简单。但实际系统里,每秒可能有几万甚至几十万笔这样的订单涌进来。怎么保证不丢单、不乱序、不冲突?这就是撮合队列要解决的问题。
核心要点:撮合队列的本质是一个「有序的等待队列」,它保证了所有订单都能按照公平的规则被处理。
撮合队列在金融交易系统中的作用
我做过几个交易所的后端系统,说实话,撮合队列是整个系统的「心脏」。它干三件事:
- 接收订单:从客户端、API网关接收买卖请求
- 排队等待:按价格、时间排序,形成有序队列
- 执行撮合:找到匹配的买卖双方,完成交易
你想想看,如果没有撮合队列,会发生什么?
比如两个买家同时出价10块买同一只股票,系统该先处理谁?如果没有队列,结果就是乱套——有人插队、有人被漏掉、有人投诉不公平。
注意:我曾经在一个项目中遇到过,因为队列设计不合理,导致高并发时订单丢失。排查了三天才发现是队列溢出导致的。从那以后,我对队列的容量和背压机制特别敏感。
核心概念:订单簿
订单簿,是撮合队列的「灵魂」。它记录了当前所有未成交的买卖订单。
订单簿分两边:
- 买单队列:所有想买的人,按价格从高到低排
- 卖单队列:所有想卖的人,按价格从低到高排
为什么这么排?因为买方当然希望价格越低越好,但为了抢到货,愿意出高价的人排前面。卖方正好相反,想卖高价,但为了尽快出手,愿意低价卖的人排前面。
嗯,这里要注意:价格优先是第一原则。同样价格,才看谁先来。
核心概念:买卖盘口
买卖盘口,就是订单簿的「快照」。它展示了当前市场上最好的买价和卖价。
举个例子:
| 买盘(Bid) | 价格 | 卖盘(Ask) |
|---|---|---|
| 100股 @ 10.01 | 10.01 | 200股 @ 10.02 |
| 300股 @ 10.00 | 10.00 | 150股 @ 10.03 |
| 500股 @ 9.99 | 9.99 | 400股 @ 10.04 |
这个表格里:
- 最高买价是10.01,有100股想买
- 最低卖价是10.02,有200股想卖
- 买卖价差是0.01元
如果这时候有人出价10.02买,或者10.01卖,就能立刻成交。这就是盘口的意义——告诉你当前市场最真实的供需情况。
个人经验:我建议你在设计盘口数据结构时,用红黑树或者跳表。因为盘口需要频繁地插入、删除、查询最优价格。数组和链表在这种场景下性能太差了。我曾经用链表实现过,结果压测到1万笔/秒就扛不住了,换成跳表后直接干到10万+。
知识体系图
下面这张图展示了撮合队列的核心知识结构:
实际项目中的坑
讲几个我踩过的坑:
- 队列溢出:高并发时订单量暴增,队列满了怎么办?我建议用有界队列 + 拒绝策略,而不是无界队列。无界队列会把内存撑爆。
- 锁竞争:撮合队列是共享资源,多线程访问时锁竞争严重。我后来改用无锁队列(Disruptor),性能提升了3倍。
- 持久化:订单进来后要不要先落盘?我的经验是:先写日志再处理。万一系统崩溃,可以从日志恢复。
避坑指南:我曾经因为没做订单去重,导致同一笔订单被撮合了两次。后果很严重——客户多买了股票,我们赔了不少钱。从那以后,我坚持在队列入口做幂等性校验。
小结
撮合队列是交易系统的基石。它负责接收订单、排队等待、执行撮合。核心概念包括订单簿和买卖盘口。
订单簿记录了所有未成交的订单,买卖盘口展示了当前最优的买卖价格。设计时要注意队列容量、锁竞争、持久化和幂等性。
说白了,撮合队列就是一个「公平的排队机制」。没有它,金融市场就乱套了。
公众号:蓝海资料掘金营,微信deep3321