在金融交易系統開發中,效能和延遲是兩個最關鍵的指標。作為一位專門從事金融科技系統開發的技術工作者,玄貓經常需要在系統架構設計時,在不同的平行處理方案間做出抉擇。今天就來分享在建構交易比對引擎時,關於系統執行緒(System Threads)和 Rust 的 Async/Await 兩種方案的深入分析。

為何 Async/Await 不總是最佳選擇

Rust 的 Async/Await 模式近年來備受歡迎,這種非同步處理方式確實在大多數網路應用場景中表現優異。當系統面臨大量 I/O 操作(如資料函式庫)時,Async/Await 能夠有效管理系統資源,讓單一執行緒處理多個請求。

然而,在建構低延遲交易系統時,玄貓發現 Async/Await 並非最佳選擇。主要原因在於:

  1. 執行緒控制的精確性
  2. 任務排程的可預測性
  3. 系統延遲的穩定性

交易比對系統的技術需求

在設計交易所的訂單比對系統時,我們需要確保:

  • 最小化處理延遲
  • 可預測的執行時間
  • 精確的任務控制
  • 核心繫結的執行效能

為了實作這些目標,玄貓選擇使用系統執行緒而非 Async/Await 模式。

實作交易比對系統

跨執行緒通訊的實作

在實作過程中,首先面臨的挑戰是如何實作高效的跨執行緒通訊。經過多次測試,玄貓發現標準函式庫道實作並不符合需求:

use crossbeam_queue::ArrayQueue;
use std::sync::Arc;

// 建立訂單佇列
let order_queue: Arc<ArrayQueue<Order>> = Arc::new(ArrayQueue::new(100));

// 傳送訂單
order_queue.push(order);

// 接收並處理訂單
while let Some(order) = order_queue.pop() {
    // 訂單處理邏輯
}

最佳化的比對引擎執行緒

在比對引擎的核心實作中,我們使用專屬的系統執行緒:

let match_system_thread_handle = std::thread::spawn(move || {
    let mut matcher_system = OrderMatcher::new(crypto_currency_id, currency_id);
    
    loop {
        // 處理佇列中的訂單
        while let Some(order) = order_queue.pop() {
            matcher_system.add_order(order);
        }
        
        // 執行訂單比對
        let order_matches = matcher_system.match_orders();
        
        // 處理比對結果
        for order_match in order_matches {
            process_match(order_match);
        }
    }
});

關鍵技術考量

在實作過程中,玄貓特別注意以下幾個技術細節:

  1. 使用 crossbeam 函式庫無鎖定的跨執行緒通訊,避免執行緒阻塞
  2. 將比對引擎繫結到特定 CPU 核心,確保處理效能的穩定性
  3. 實作精確的執行緒控制機制,而非依賴非同步執行器的排程

效能最佳化與監控

在實際運作中,系統執行緒方案展現出明顯優勢:

  • 延遲表現更加穩定,標準差明顯低於 Async/Await 方案
  • 資源使用更可預測,便於系統監控與效能調校
  • 執行順序可控,確保高優先順序訂單得到及時處理

系統擴充套件性設計

雖然採用系統執行緒方案,但玄貓同時也注意到系統的擴充套件性需求。在設計時採取以下策略:

  • 實作模組化的比對引擎架構
  • 建立彈性的執行緒池管理機制
  • 設計可擴充套件的訂單路由系統

最終的系統架構不僅滿足了低延遲需求,還保持了良好的可擴充套件性。這個案例充分說明瞭在金融科技領域,技術方案的選擇需要深入考慮業務場景的特殊需求,而非盲目追隨技術趨勢。

在金融交易系統這類別對延遲極其敏感的場景中,系統執行緒方案往往能提供更好的效能保證。不過這並不意味著 Async/Await 沒有其價值,而是要根據具體場景選擇最適合的技術方案。選擇合適的平行處理策略,需要對系統需求有深入的理解,並且願意在不同方案間進行細緻的權衡。

在建構加密貨幣交易所的過程中,訂單比對系統的效能與可靠性至關重要。今天玄貓要分享如何運用Rust語言開發一個高效能的訂單比對引擎,重點探討執行緒管理、CPU繫結等關鍵技術實作。

系統架構設計

訂單比對系統的核心架構包含以下幾個關鍵元件:

  1. 訂單比對引擎(OrderMatcher)
  2. 儲存系統(StorageSystem)
  3. 資產管理(AssetSystem)
  4. 帳戶系統(AccountSystem)

讓我們先來看訂單比對引擎的核心實作:

let matcher_thread = std::thread::spawn(move || {
    loop {
        if let Some(order) = order_queue.pop() {
            let order_match = process_order(order);
            let _ = order_match_queue.push(order_match);
        }
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
});

** **

  • 建立一個無限迴圈的執行緒,專門處理訂單比對
  • 從訂單佇列(order_queue)取出訂單進行處理
  • 處理完的結果放入比對結果佇列(order_match_queue)
  • 使用睡眠機制避免CPU使用率過高

CPU繫結最佳化

為了最大化系統效能,玄貓採用了CPU繫結技術,確保比對引擎在固定的處理器核心上執行:

impl MatcherSystem {
    pub fn start(crypto_currency_id: u64, currency_id: u64, core_id: CoreId) -> MatcherSystem {
        let _match_system_thread_handle = std::thread::spawn(move || {
            let ok = core_affinity::set_for_current(core_id);
            if ok {
                let mut matcher_system = OrderMatcher::new(crypto_currency_id, currency_id);
                loop {
                    // 處理訂單邏輯
                }
            } else {
                panic!("Failed to set core affinity");
            }
        });
    }
}

** **

  • 使用core_affinity函式庫CPU繫結
  • 將比對系統繫結到指定的處理器核心
  • 確保訂單處理在同一核心上執行,減少連貫的背景與環境切換開銷
  • 失敗時立即終止程式以確保系統穩定性

完整系統整合範例

以下是一個完整的系統整合範例,展示如何將各個元件組合起來:

fn main() {
    let storage_system = Arc::new(StorageSystem::new());
    let mut assets_system = AssetSystem::new(storage_system.clone());

    // 初始化貨幣資產
    if assets_system.get_currencies().len() == 0 {
        let _ = assets_system.create_currency(Currency { 
            id: 0, 
            symbol: "USD".to_string() 
        });
    }

    // 初始化加密貨幣
    if assets_system.get_crypto_currencies().len() == 0 {
        let _ = assets_system.create_crypto_currency(CryptoCurrency { 
            id: 0, 
            symbol: "BTC".to_string() 
        });
    }

    let assets_system = Arc::new(assets_system);
    let mut accounts_system = AccountSystem::new(
        storage_system.clone(), 
        assets_system.clone()
    );

    // 設定測試帳戶
    if storage_system.load_accounts().len() == 0 {
        let account1_id = accounts_system.create_account(Account { 
            id: 0, 
            name: "Alice".to_string(), 
            timestamp: SystemTime::now() 
        });
        
        accounts_system.add_currency_to_account(account1_id, currency_id, 100000.0);
    }
}

** **

  • 使用Arc智慧指標實作分享狀態
  • 初始化必要的系統元件
  • 建立測試帳戶並設定初始資產
  • 確保系統啟動時的資料一致性

在實際開發過程中,玄貓發現將訂單比對邏輯限制在單一執行緒中執行,不僅簡化了系統複雜度,更能確保訂單處理的順序性和一致性。這種設計避免了多執行緒環境下可能出現的競爭條件,同時透過CPU繫結提升了系統效能。

這個設計的優勢在於它的可預測性和可控性。透過單一執行緒處理訂單比對,我們無需處理複雜的同步機制,系統行為更容易除錯和維護。CPU繫結則進一步確保了執行效能的穩定性,特別是在高頻交易場景中。

經過實際執行測試,這套系統展現出優異的效能表現,能夠穩定處理高並發的訂單比對需求。對於有意建構交易系統的開發者而言,這個開放原始碼實作提供了一個紮實的基礎框架。 接續前文,讓我們來仔細解析這段程式碼的核心功能:

訂單處理與撮合功能解析

訂單建立與撮合流程

// 建立市價買單
let order1 = order_system.create_order(Order {
    id: 0,
    account_id: account1_id,
    trade_type: TradeType::Buy,
    price_type: PriceType::Market,
    execution_type: ExecutionType::Full,
    crypto_currency_id: crypto_currency_id,
    currency_id,
    quantity: 0.5,
    status: OrderStatus::Open,
    timestamp: SystemTime::now()
});

// 建立限價賣單
let order2 = order_system.create_order(Order {
    id: 0,
    account_id: account2_id,
    trade_type: TradeType::Sell,
    price_type: PriceType::Limit(50000.00),
    execution_type: ExecutionType::Partial,
    crypto_currency_id: crypto_currency_id,
    currency_id,
    quantity: 1.0,
    status: OrderStatus::Open,
    timestamp: SystemTime::now()
});

** **

  1. 此段程式碼展示了兩種不同類別訂單的建立:
    • 市價買單:設定購買0.5單位的加密貨幣,採用市場價格成交
    • 限價賣單:設定以50000.00的價格賣出1.0單位的加密貨幣,允許部分成交

訂單撮合與執行邏輯

loop {
    while let Some(order_match) = matcher_system.get_order_match() {
        tracing::info!("OrderMatch: Buy Order Id: {} Sell Order Id: {} Quantity: {} Price: {}", 
            order_match.buy_order_id, 
            order_match.sell_order_id, 
            order_match.quantity, 
            order_match.price
        );
        
        order_system.create_order_history(&order_match, &mut accounts_system);
        print_accounts(storage_system.clone());

        // 檢查帳戶餘額並建立新訂單
        if storage_system.get_account_currency(account1_id, currency_id).unwrap().balance > 0.0 {
            let order = order_system.create_order(Order {
                id: 0,
                account_id: account1_id,
                trade_type: TradeType::Buy,
                price_type: PriceType::Market,
                execution_type: ExecutionType::Full,
                crypto_currency_id: crypto_currency_id,
                currency_id,
                quantity: 0.5,
                status: OrderStatus::Open,
                timestamp: SystemTime::now()
            });
            matcher_system.add_order(order);
        }
    }
    std::thread::sleep(std::time::Duration::from_secs(1));
}

** **

  1. 撮合系統持續運作,尋找可以配對的訂單
  2. 當發現撮合機會時:
    • 記錄交易細節(買賣訂單ID、成交數量和價格)
    • 建立訂單歷史記錄
    • 更新帳戶狀態
  3. 系統會檢查帳戶餘額,若有足夠資金則自動建立新的市價買單
  4. 每次迴圈間隔1秒,避免系統資源過度使用

帳戶資訊顯示功能

fn print_accounts(storage_system: Arc<StorageSystem>) {
    for account in storage_system.load_accounts() {
        let datetime: DateTime<Local> = account.timestamp.into();
        tracing::info!{
            "AccountId: {} Name: {} Timestamp: {}",
            account.id,  
            account.name, 
            datetime.format("%Y-%m-%d %H:%M:%S").to_string()
        };
        
        // 顯示法幣餘額
        for account_currency in storage_system.get_account_currency_by_account_id(account.id) {
            tracing::info!{
                "CurrencyId: {} Symbol: {} Balance: {:.2}", 
                account_currency.id, 
                storage_system.get_currency(account_currency.currency_id).unwrap().symbol, 
                account_currency.balance
            };
        }
        
        // 顯示加密貨幣餘額
        for account_crypto_currency in storage_system.get_account_crypto_currencies_by_account_id(account.id) {
            tracing::info!{
                "CryptoCurrencyId: {} {} Amount: {}", 
                account_crypto_currency.id, 
                storage_system.get_crypto_currency(account_crypto_currency.crypto_currency_id).unwrap().symbol, 
                account_crypto_currency.quantity
            };
        }
    }
}

** **

  1. 帳戶資訊顯示功能提供完整的帳戶狀態報告,包含:
    • 帳戶基本資訊(ID、名稱、時間戳記)
    • 法幣餘額資訊(幣種ID、符號、餘額)
    • 加密貨幣餘額(幣種ID、符號、數量)
  2. 使用tracing模組進行日誌記錄,確保所有交易活動可追蹤
  3. 時間戳記格式化為本地時間,提升可讀性

這套交易系統展現了完整的訂單生命週期管理,從訂單建立、撮合到執行,並具備即時的帳戶資訊追蹤功能。系統設計考慮了並發處理、資料一致性和可追蹤性等關鍵要素,適合作為加密貨幣交易平台的核心引擎。

// 建立訂單配對的結構
pub struct OrderMatch {
    pub buy_order_id: i32,
    pub sell_order_id: i32, 
    pub quantity: f64,
    pub price: f64
}

// 訂單執行類別
#[derive(Debug)]
pub enum ExecutionType {
    Full,    // 全部執行
    Partial  // 部分執行
}

// 訂單狀態
#[derive(Debug)]
pub enum OrderStatus {
    Open,     // 未成交
    Closed,   // 已成交
    Canceled  // 已取消
}

// 訂單價格類別
#[derive(Debug)]
pub enum PriceType {
    Market,       // 市價單
    Limit(f64)    // 限價單及價格
}

// 交易類別
#[derive(Debug)] 
pub enum TradeType {
    Buy,   // 買入
    Sell   // 賣出
}

// 訂單結構
#[derive(Debug)]
pub struct Order {
    pub id: i32,                    // 訂單ID 
    pub account_id: i32,            // 帳戶ID
    pub trade_type: TradeType,      // 交易類別
    pub price_type: PriceType,      // 價格類別
    pub execution_type: ExecutionType,  // 執行類別
    pub crypto_currency_id: i32,    // 加密貨幣ID
    pub currency_id: i32,           // 法幣ID
    pub quantity: f64,              // 交易數量
    pub timestamp: SystemTime,      // 訂單時間戳
    pub status: OrderStatus         // 訂單狀態
}

// 配對引擎實作
pub struct Matcher {
    pub orders: Vec<Order>
}

impl Matcher {
    // 建立新的配對引擎
    pub fn new() -> Self {
        Matcher { 
            orders: Vec::new() 
        }
    }
    
    // 訂單配對邏輯
    pub fn match_orders(&mut self) -> Vec<OrderMatch> {
        let mut matches = Vec::new();
        
        // 遍歷所有未成交訂單
        for buy_order in self.orders.iter_mut().filter(|o| matches!(o.trade_type, TradeType::Buy)) {
            if buy_order.status != OrderStatus::Open {
                continue;
            }
            
            // 尋找比對的賣單
            for sell_order in self.orders.iter_mut().filter(|o| matches!(o.trade_type, TradeType::Sell)) {
                if sell_order.status != OrderStatus::Open {
                    continue;  
                }
                
                // 檢查是否可以配對
                if let Some(match_quantity) = self.can_match(buy_order, sell_order) {
                    // 建立配對結果
                    let order_match = OrderMatch {
                        buy_order_id: buy_order.id,
                        sell_order_id: sell_order.id,
                        quantity: match_quantity,
                        price: match sell_order.price_type {
                            PriceType::Limit(price) => price,
                            PriceType::Market => 0.0
                        }
                    };
                    
                    matches.push(order_match);
                }
            }
        }
        
        matches
    }
}

內容解密:

  1. 核心資料結構
  • OrderMatch: 定義訂單配對的結果,包含買賣雙方ID、成交數量和價格
  • ExecutionType: 訂單執行類別列舉,分為全部執行和部分執行
  • OrderStatus: 訂單狀態列舉,包含未成交、已成交和已取消
  • PriceType: 價格類別列舉,分為市價單和限價單
  • TradeType: 交易類別列舉,分為買入和賣出
  • Order: 訂單完整資訊結構體
  1. 配對引擎實作
  • Matcher: 配對引擎結構體,內含訂單向量
  • new(): 建立新的配對引擎例項
  • match_orders(): 核心配對邏輯,遍歷未成交訂單並尋找比對
  1. 配對邏輯特點
  • 買賣訂單分開處理,提高效率
  • 狀態檢查確保只處理未成交訂單
  • 支援市價單和限價單的不同配對邏輯
  • 彈性的部分成交機制
  1. 安全性考量
  • 使用強型別避免資料混亂
  • 狀態管理清晰,避免重複配對
  • 價格和數量使用 f64 確保精確度
  1. 效能最佳化
  • 使用 filter 進行高效過濾
  • 避免不必要的資料複製
  • 採用向量儲存提升查詢效率

這個交易配對系統的設計重點在於:

  1. 清晰的資料結構設計
  2. 靈活的配對邏輯
  3. 良好的型別安全性
  4. 優秀的效能表現

這樣的設計讓系統既保持了彈性,又確保了穩定性,適合作為加密貨幣交易所的基礎架構。 讓我們繼續分析這段加密貨幣交易引擎的日誌記錄。從日誌可以看出系統正在處理一筆位元幣的撮合交易,我們來仔細解析交易過程中的關鍵細節。

交易撮合過程

在這次交易中,系統記錄了一個市價買單和限價賣單的撮合過程:

// 買單詳情
Order { 
    id: 3,
    account_id: 1,  // Alice
    trade_type: Buy,
    price_type: Market,
    execution_type: Full,
    quantity: 0.5,
    // 其他欄位省略
}

// 賣單詳情
Order {
    id: 2, 
    account_id: 2,  // Bob
    trade_type: Sell,
    price_type: Limit(50000.0),
    execution_type: Partial,
    quantity: 0.5,
    // 其他欄位省略
}

這筆交易的主要特點:

  • 交易量:0.5 BTC
  • 成交價:50,000 USD
  • 買方(Alice)使用市價單
  • 賣方(Bob)使用限價單,限價為 50,000 USD

帳戶餘額變化

系統記錄了交易前後的帳戶餘額變化:

Alice的帳戶:

  • 初始 USD 餘額:100,000
  • 交易後 USD 餘額:50,000(扣除了 50,000 購買 0.5 BTC)
  • 收到 0.5 BTC

Bob的帳戶:

  • 初始持有 0.5 BTC
  • 交易後獲得 25,000 USD
  • BTC 餘額減少 0.5

系統執行特點

  1. 交易引擎採用多執行緒架構:

    • 使用 ThreadId(01) 處理交易紀錄
    • 使用 ThreadId(02) 處理訂單撮合
  2. 完整的歷史記錄追蹤:

    • 系統為每次餘額變動建立歷史記錄
    • 使用精確的時間戳記錄所有操作
  3. 訂單執行類別:

    • 買單為全額執行(Full)
    • 賣單允許部分執行(Partial)

這個交易系統展現了良好的設計特點:精確的餘額追蹤、完整的歷史記錄、合理的多執行緒處理,以及靈活的訂單撮合機制。系統能夠安全與有效地處理不同類別的訂單,並維護交易雙方的帳戶狀態。

真實的交易場景中,這種詳細的日誌記錄對於系統監控、問題排查和交易稽核都極為重要。每一筆交易都被完整記錄,包括交易前後的帳戶狀態,這不僅確保了交易的透明度,也為可能的爭議處理提供了依據。

在多年開發金融交易系統的經驗中,玄貓觀察到交易引擎的效能與可靠性是系統成功的關鍵。今天就讓我們透過分析一個用Rust實作的交易引擎日誌,探討其架構設計與效能最佳化方案。

系統核心元件分析

帳戶系統(AccountSystem)

帳戶系統負責管理使用者資產,包含以下核心功能:

  • 帳戶管理與餘額追蹤
  • 法幣與加密貨幣餘額維護
  • 交易歷史記錄

從日誌可見帳戶操作範例:

// 帳戶資訊日誌
AccountId: 2 Name: Bob Timestamp: 2024-07-08 19:55:28
CurrencyId: 2 Symbol: USD Balance: 50000.00
CurrencyHistoryId: 3 Balance: 25000.00 Timestamp: 2024-07-08 19:55:29

這段日誌顯示系統正確追蹤了帳戶餘額變動,實作了即時更新與歷史記錄功能。

資產系統(AssetSystem)

資產系統處理各類別資產的管理:

// 加密貨幣餘額追蹤
CryptoCurrencyId: 1 BTC Amount: 0
CryptoCurrencyHistoryId: 1 Quantity: 1 Timestamp: 2024-07-08 19:55:28
CryptoCurrencyHistoryId: 3 Quantity: 0.5 Timestamp: 2024-07-08 19:55:29

訂單配對系統(MatcherSystem)

訂單配對系統負責處理交易訂單的配對:

// 訂單配對日誌
Before Matching
Buy Order: Order { 
    id: 4, 
    account_id: 1, 
    trade_type: Buy, 
    price_type: Market, 
    execution_type: Full, 
    crypto_currency_id: 1, 
    currency_id: 1, 
    quantity: 0.5, 
    timestamp: SystemTime { ... }, 
    status: Open 
}

儲存系統(StorageSystem)

系統採用redb作為儲存引擎,具備以下特點:

  • ACID特性保證
  • 高效的key-value儲存
  • 內嵌式設計,降低系統複雜度

效能最佳化建議

根據日誌分析,玄貓提出以下最佳化建議:

訂單配對最佳化

目前系統僅支援市價買入與限價賣出的完全/部分配對,建議擴充套件支援:

  • 實作全類別訂單的配對邏輯
  • 引入訂單優先順序機制
  • 實作更靈活的部分成交策略

儲存系統擴充套件

為提升系統擴充套件性,建議增加:

  • 分片(Sharding)機制
  • 分散式事務處理
  • 分散式儲存支援

效能監控強化

建議加入更完整的效能監控機制:

  • 詳細的交易延遲統計
  • 系統資源使用率監控
  • 即時警示機制

在開發高頻交易系統時,玄貓發現效能監控對於系統穩定性至關重要。透過完整的監控機制,我們能夠及早發現並解決潛在問題。

交易引擎是金融科技領域中最具挑戰性的系統之一。透過Rust的高效能特性,結合完善的系統架構設計,我們能夠開發出兼具可靠性與效能的交易平台。持續最佳化與改進將是系統保持競爭力的關鍵。