幾年前,在通信領域的技術咨詢經歷,初步了解到預分配內存管理機制,其對于性能的改善是多么的明顯。最近,也從點點滴滴的金融科技的領域,看到了高頻交易所需要的低延時架構技術(當然了,國內在該領域受限于特色背景),也有點如出一轍的味道。而在未來,“元宇宙” 可能會換個新的名詞,但是呢,它依舊也需要一系列的低延遲架構設計模式。
在探索的過程中,有感于一系列反直覺的架構模式/設計模式。于是乎,作為低延遲架構領域的 “門外漢”,便結合著自己的理解,以及手頭上的資料和書籍,做一個初步的整理和調研。
作為一個“新手”,難免如出現錯誤理解,也歡迎各位讀者指正。
低延遲技術概覽
低延遲(low latency)(https://www.phodal.com/blog/explore-low-latency-architecture/)顧名思議是計算系統或網絡以最小延遲提供響應的能力。從數據的角度來考慮,如果我們想最大程度降低延遲,那么就需要關注到每一個層次的數據處理。所以,它會涉及到一系列方方面面的領域,諸如于:
-
網絡傳輸與硬件
-
-
數據傳輸。如微波、光纖、網線等
-
路由機制。
-
網絡與硬件側。網絡協議、網卡等,專用處理器等,如 FPGA,
-
-
系統編程策略
-
-
操作系統。(從通用型操作系統到專用型操作系統) CPU 緩存、內核調度等。
-
語言側。平衡高性能的語言與規模化。
-
其它。如內存管理策略等。
-
-
應用軟件
-
-
架構側。事件驅動型架構,如 LMAX
-
應用開發側。高性能的數據結構(如集合)、通過設計模式提升性能等。
-
可視化側。密集計算下沉 WASM 等。
-
設計模式。采用無鎖和無阻塞設計模式,降低、消除操作系統信號延遲
-
受限于我在這個領域的了解有限,應該還要包含其它的內容,有待未來進一步探索。作為大學專業是通信領域相關的工程師,對于網絡傳輸與硬件側,我還是相當有興趣的。
當然了,一些奇技淫巧并不在我們這里的討論范圍,諸如于數據包提前處理機制。
系統編程策略
操作系統
在操作系統側,基本模式是定制型的操作系統,這也特別好理解。其次,底層的模式是:基于 linux 內核的定制型操作系統搭配特定的硬件,以及特定私有的網絡協議棧。由于 Linux 的網絡性能不好,所以內核旁路技術的目的是:不再讓內核(TCP/IP 協議棧)處理數據包。用自己實現的相同功能的代碼來處理,從用戶空間直接訪問和控制設備內存,避免數據從設備拷貝到內核,再從內核拷貝到用戶空間。所以在大量的高頻交易 (HFT) 解決方案里,使用帶有 OpenOnLoad 框架的 Solarflare 網卡成了一個非常好的選擇。
再往上則是,圍繞于 Linux 內核的其它定制,諸如于內存分布管理、進程調度、優化數據結構以利用處理器緩存等。
語言
從現有的應用情況而言,C、C++ 基本上是在低延遲領域的代表性語言。當然,在不并需要那么嚴苛速度的場景下,諸如國內環境,那么 JAVA 也是一個非常不錯的語言 —— 快速呼朋喚友。畢竟,資深的 C++ 程序員是稀缺的。
良好的設計模式 + 整潔的代碼,配合上經過特制的 JVM 和架構,同樣工程造價下,Java 程序的速度還是可以接近 C++。
內存管理策略
在傳統的通信領域里,一種常見管理內存的方式是:預分配內存,它可以減少分配內存所需的時間,進而提升性能。也因此,編寫一個自定義的 malloc 便是這個領域的好選擇,而諸如于采用 google 的 TCMalloc,又或者是 Jemalloc 也是一個不錯的選擇。
既然,C/C++ 語言有內存分配的問題,那么自動 GC 的 Java 語言也有相似的問題。在 GC 的過程中,為了進行準確的計數,應用程序線程需要暫時“凍結”,也就是 GC 停頓。應對于此,通常有兩個做法:無 GC 又或者是更好的 GC 算法。而要對 JVM 進行優化并不是一件容易的事,所以直接采用諸如于 Azul Systems 的 Zing 引擎,又或者是 GraalVM,還能支持 AoT 編譯的 VM —— 可以將字節碼轉換為機器碼,以提升性能。這又造成了另外一個問題,AoT 意味著失去了自適應即時(JIT)編譯,會影響到我們習慣的各種依賴注入等特性。簡單來說,你可能用不了 Spring,或者你的 Spring 應用需要遷移。
這方面研究的路很長,都有待我在未來有空進一步展開研究。
應用軟件架構側
從架構層面來考慮,基于事件驅動架構的無狀態軟件架構,諸如于 LMAX 架構這樣的框架就能提供非常不錯的參考。其主要由三部分組成:高并發框架(Disruptor)、事件溯源(Event Sourcing)、完全內存(in-memory)駐留風格等。其中,關于持續久化部分是相當反直覺的,既然事務性數據庫是個瓶頸,那就不用數據庫,將事件流記錄到文件系統。以內存為中心,持久化的事件作為輔助,便是這種架構模式的一大特征。
應用開發
Java 框架
回到上面說的 AoT 和 JIT 的問題,如果我們想到一個啟動更快的框架,那么我們就不能使用 Spring 框架。于是乎 現代化的微服務架構框架 Micronaut、Kube.NETes 原生的 Java 框架 Quarkus,提供了兩種不同的思路。Micronaut 在編譯時依賴流入,可以加快應用程序的啟動,降低內存的使用,進而提升響應速度,也可以利用 AoT 帶來的性能加強。當然,這也意味著編程模式上會有一系列的變化。
高性能數據結構
在 Java 側,為了構建高性能的 Java 應用,還需要在大數據結構上做一些優化,諸如于集合操作(List、Set、Bag),像 Agrona、fastutil 便是針對于 Java Collections Framework 做的擴展。同樣,高盛的 JVM 架構組在多年前貢獻給 Eclipse 基金會的:Eclipse Collections,便是一個旨在提升集合操作的 Java 庫。
可視化側
在可視化方面,如果有大量的圖表需要展示,那么就需要考慮將密集計算下沉到 WASM 的方式。在這一點上 Perspective 提供了一個非常不錯的思路,使用 Rust 結合高性能的 C++ 數據結構設計,提供 GUI + WASM 的封裝,以實現更快的計算速度。
PS:待我在下一篇文章中進一步展開。
其它
數據處理。理論上,我們還應該考慮對于數據的處理,諸如于不同存儲介質應對實時數據、歷史數據等等。
小結
在參考資料上,推薦一下《Developing High-Frequency Trading Systems》,它是我在編寫此文時,嘗試云覆蓋更多維度時,所查找到的比較系統介紹的書籍。
-
《Developing High-Frequency Trading Systems》
-
《Linux性能優化(九)——Kernel Bypass》
-
《為什么協議棧在內核中實現》(中文翻譯版)
-
《為什么我們選擇Java開發高頻交易系統?》 (中文翻譯版)
-
《LMAX架構》(中文翻譯版)