數字貨幣交易所開發筆記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 系統接口
撮合系統主要為使用者提供訂單的下單和查詢服務、交易行情的實時反饋功能以及系統狀態的監控查看服務。因此系統需要實現預留的接口主要包括:
■ 下單接口
■ 訂單查詢接口
■ 行情查詢接口
■ 系統控制接口和運行狀態查詢接口等
總結
從總體設計入手,將撮合業務處理從數據庫遷移至內存中,同時釆用多機熱備份技術解決內存撮合技術的易失性問題,最終提出內存狀態機復制方案作為高可靠髙性能撮合系統的實現路線。撮合技術的具體實現將在下一章進行詳細論述。