数字货币交易所开发笔记3-撮合引擎开发
对于撮合技术的发展,目前撮合技术主要是从数据库撮合技术向内存撮合技术发展,这是因为数据库撮合技术越来越无法满足高频交易对于高可靠性、高性能、强安全性、可扩展性以及易维护性的需求。本文就码云上开源的数字货币交易所源码——CoinExchange进行撮合交易系统的解读。
本文参考了
1、开源数字货币交易所CoinExchange(https://gitee.com/cexchange/CoinExchange)
2、交易系统设计架构(freshmanTechnology博文:https://yq.aliyun.com/articles/60653)
系统总体设计
2.1 层次设计
一般而言,数字货币交易所的交易撮合系统中包括以下几个核心模块:
■ 用户:用户委托报价与数量,生成订单发送至交易平台。
■ 网关:负责收集用户订单,并将其派发给撮合引擎。
■ 撮合引擎:交易系统中的核心部分,用于接收订单并根据业务逻辑实现订单,撮合同时生成交易记录,随后给予用户交易结果反馈。
■ 行情引擎:接收撮合交易引擎的处理结果,将撮合的交易数据持久化到数据库,同时定时生成多时间周期的K线数据(开盘价、收盘价、交易量、最高价、最低价)。
■ 数据库:用来存放交易过程中的订单和交易记录,实现数据持久化。
此外,本文根据不同类型的数字货币交易产品(现货、合约、期货、杠杆)将撮合模块划分为若干业务分区,每个分区独立进行撮合,彼此不受影响。本章的总体设计围绕撮合引擎层以及撮合引擎与网关层、数据库层的交互方式的总体设计。
2.2 撮合交易算法
如图2.1所示,撮合引擎的核心业务模块就是撮合交易算法撮合交易算法的任务一方面是完成对客户所下订单进行公平合理的排列和撮合功能,也要保证撮合算法的公平性、高效性以及扩展性等。由于不同金融交易系统的撮合业务各有不同,因此本节对通用的撮合交易算法进行概括性描述。
2.3 订单队列
撮合交易的重要组成部分就是买卖订单,通过对买卖订单进行撮合最后形成交易记录。所以对无法立刻完成撮合的订单,需要有买入队列和卖出队列保存订单。队列按照“价格优先、同价格下时间优先”的原则。买入队列按照委托价格从低到高的顺序,卖出队列则按照委托价格从低到高的顺序排列,如图2.2所示:
2.4 撮合顺序
撮合引擎接收到新的买入订单,则会到卖出队列的头部查找是否存在符合价格规则的卖出订单,如果存在卖出价格小于或等于买入价格的订单,则从队列中取出此订单并撮合成一笔交易;如果卖出队列为空或队列头部不满足价格关系,则将买入订单插入买入队列中,由于买入队列是按照价格与时间先后进行排序,所以新插入的订单会经过一次排序插入到买入队列的相应位置。
相同的,当撮合引擎接收到新的卖出订单,则会到买入队列的头部査找是否存在符合价格规则的买入订单,如果存在买入价格大于或等于卖出价格的订单,则从订单队列中取出此订单并撮合成一笔交易;如果买入队列为空或队列头部不满足价格关系,则将卖出订单插入到卖出队列中,由于卖出队列也是按照价格与时间先后进行排序的,所以新插入的订单会经过一次排序插入到卖出队列的相应位置。
结合买卖订单情况,撮合算法流程如图2.3所示。从图2.3所示的撮合顺序可知,买卖队列的有序性是保证撮合顺序的确定性的基础,并且撮合过程中每笔订单都可以撮合出当前最优交易。
2.5 内存撮合
当前的数据库撮合技术的性能低下的原因在于过多与数据库交互,使得I/O很多,系统整体处理速度同时受数据库事务逻辑约束。
本文釆用内存撮合技术,通过最大程度去除与数据库的交互过程,将整个错和逻辑放在内存中进行(如图2.4所示)。因此比数据库撮合技术少了许多I/O交S 间,在性能上可以大幅提升撮合速度;例是内存撮合的弊端就是由于内存的易失性,服务器出现故障停机时,所有的交易数据将会丢失,系统的可靠性以及一致性都相应大幅降低。因此本文在提高内存撮合技术可靠性的方面采用丫多机热备份及分布式一致性技术作为补充,从而获得内存撮合技术的高性能以及数据库撮合技术的数据持久性。
通过釆用多机热备份技术,降低了单一内存撮合引擎故障时系统不可用的问题,但仍旧无法提供100%的可用性,因为当出现大规模服务器集群故障时,仍旧存在服务不可用的可能性,但在实际生产环境中,三台互为备份的服务器就可以提供较高的可以用于生产环境的可靠性。
2.6 内存状态机复制
由于多机热备份技术引入了多台互为热备份的撮合引擎,根据撮合系统设计以及撮合逻辑要求,需要保证服务器之间的数据一致,这就需要保证多服务器之间一致性,这也是本文难点之一。
本文提出一种内存状态机复制方案,即将撮合算法视作一个确定性状态机,将其复制多份并部署到撮合系统中的多台撮合引擎中。每个撮合引擎副本从相同的初始状态开始运行,当撮合系统收到网关发来的订单时,系统中的每个撮合引擎都会撮合这个订单,并依次产生交易记录,同时更新确定性撮合算法状态机的独立状态。通过这样的方式,当撮合系统正常运转时,每个撮合引擎副本都会具有相同的结果状态;当撮合系统出现故障或异常时,撮合引擎就会出现状态的不一致情况,换句话说一旦撮合系统的结果或状态出现了不一致的情况就可以断定系统出现了异常。
2.7 关键技术点
本文为了实现这样的内存状态机复制撮合系统,将撮合系统划分为以下组成关键技术点
■ 将确定性撮合算法状态机服务部署到多个独立撮合引擎
■ 接收网关订单,并作为确定性撮合算法状态机的输入
■ 根据撮合算法需求,选择一种订单排序方式
■ 每个撮合引擎对按照排序方式排序过的订单进行撮合
■ 将确定性撮合算法状态机输出的交易记录作为给用户或数据库的响应
■ 监控撮合引擎副本的状态或输出的差别
2.8 实现方案
为实现基于内存状态机复制的撮合系统,本文主要通过以下方案实现状态机复制的关键技术点:
■ 采用原子多播解决撮合引擎订单的可靠多播与全局有序性
■ 采用基于无锁订单队列的流水线撮合技术提供快速的订单撮合
■ 采用异步一致性持久化技术实现与数据库的交互
■ 采用失效备援技术对撮合引擎集群进行状态监控并保证系统的容错能采用进度追赶技术解决将故障撮合引擎的恢复或新撮合引擎的加入
2.9 系统架构
2.9.1 系统硬件体系架构
典型的高可靠高性能撮合模型硬件架构如图2.5所示,系统由n台客户端、N台网关、X个产品集群(每个集群由2至3台撮合引擎组成,负责响应产品订单的处理)、一个交易记录数据库和可选的监视系统组成。其中客户端连接到相应网关,网关负责接收客户端提交的订单,并根据订单相关的金融产品类别,转发到相对应的产品集群。产品集群中所有撮合引擎均接收网关发送的订单,根据撮合业务规则,将其撮合并回馈消息给网关和客户端,同时将撮合生成的交易记录持久化到交易记录数据库中。
2.9.2 系统软件体系架构
如图2.6所示,高可靠高性能撮合模型主要由表示层、转发层、业务层和数据层组成。其核心部分业务层主要由撮合引擎集群组成,每个撮合引擎采用原子多播将订单定序后进行撮合处理,并结合无锁订单队列实现高效流水线撮合,最后结果写入本地日志。整个业务流程由消息传递总线将消息反馈给转发层。转发层则根据产品转发规则将订单转发给相应撮合引擎集群;而撮合引擎将本地日志中的交易记录读取到异步持久化代理进程中,并进而与数据层的异步持久化写入进程通信,并最终持久化到数据库中。本地日志增强了撮合系统数据的可靠性,在出现故障后,数据仍就可以从本地日志中恢复;而界步的持久化机制则提高了数据的持久化吞吐率。
2.9.3 撮合引擎架构
为了使系统可扩展易维护,撮合引擎由原子多播订单定序模块、撮合处理器模块、交易记录日志模块和内存数据组成,每个模块根据功能业务划分。其中各部分主要有以下功能:
■ 交易订单接收线程:负责从网关接收订单,并完成原子多播定序流程。
■ 交易订单发送线程:将定序完成的订单发送给相关撮合业务线程。
■ 交易信息发送线程:将订单交易状态反馈给网关。
■ 外围业务逻辑线程:进行撮合数据的准备处理,更新内存订单数据。
■ 撮合业务逻辑线程:根据确定性撮合算法撮合接收的订单。
■ 交易行情发布线程:处理内存行情信息并发布给网关。
■ 同步日志写线程:将订单撮合产生的交易记录同步持久化到本地日志文件。
■ 异步持久化代理进程:异步将日志文件中的数据读取并持久化到数据库。
■ 订单信息:存储订单的相关价格、数量、用户、限制、类型和状态等信息。
■ 交易行情信息:撮合交易过程中的交易行情信息。
2.9.4 系统接口
撮合系统主要为使用者提供订单的下单和查询服务、交易行情的实时反馈功能以及系统状态的监控查看服务。因此系统需要实现预留的接口主要包括:
■ 下单接口
■ 订单查询接口
■ 行情查询接口
■ 系统控制接口和运行状态查询接口等
总结
从总体设计入手,将撮合业务处理从数据库迁移至内存中,同时釆用多机热备份技术解决内存撮合技术的易失性问题,最终提出内存状态机复制方案作为高可靠髙性能撮合系统的实现路线。撮合技术的具体实现将在下一章进行详细论述。