打造更快未來:銀行如何利用 JDK 22 的巧妙互通技巧與 Rust 擦出火花

了解 JDK 22 的 Foreign Function and Memory API 如何讓銀行在不擾動 Java 單體架構的情況下整合 Rust 以實現高效能交易。更快、更省、更環保。

打造更快未來:銀行如何利用 JDK 22 的巧妙互通技巧與 Rust 擦出火花

想像一下,您的 Java 交易平台運作順暢時,JVM 突然決定要「小休片刻」,觸發垃圾回收暫停。數百萬英鎊的潛在交易就此溜走,而系統卻在喘息。我們都看過事後檢討報告:撮合引擎在資料饋送高峰時凍結 800 毫秒;風險引擎因為一次完整 GC 選擇在錯誤時刻清理,而錯過保證金追繳窗口。銀行已忍受這類問題多年,像幼兒緊抱安慰毯一樣死守單體 Java 系統。但現在 JDK 22 提供了一種既有趣又低調的方式,讓您可以在不發動全面革命或觸發合規危機的情況下,悄悄引入 Rust。

老掉牙的藉口已經越來越站不住腳。當競爭對手悄悄實現更好的執行時間和更低的雲端帳單時,「它能用」已不再是策略。監管機構對營運韌性的提問越來越嚴苛。人才庫正在轉變。而您付錢購買的硬體,大部分時間都在等待下一次 GC 週期結束。

秘密武器:Foreign Function and Memory API

Two interlocking metallic mechanisms joined by a zero-copy conduit of light
JDK 22 FFM 作為連接傳統核心與原生模組的明亮零複製橋樑。

關鍵成分是已在 JDK 22 正式敲定的 Foreign Function and Memory API(JEP 454)。忘掉過去 JNI 那套脆弱的舞蹈、可怕的指標運算、手動參考計數,以及讓每次安全審查都變成數週苦差事的各種麻煩。這套新工具讓您的 Java 程式碼可以直接呼叫由 Rust 編譯的共享物件原生函式庫,實現零複製資料交換,並提供真正有意義的編譯時期安全檢查。

這就像在不拆掉原有線路的情況下,給您那台老舊 JVM 一套電動工具。您保留運作良好的部分(周邊的 Scala 或 Kotlin 業務邏輯、報表管線、監管介接),只加速那些真正造成痛點的區塊。訂單撮合、風險引擎或即時報價等熱路徑留在 Rust 中,其他部分則繼續無感運作。多家一線機構已經這樣做過,將 Rust 微服務無縫置入 Java 單體架構,並在受監管的變更窗口內完成零停機轉換。

在底層,您會獲得妥善管理生命週期的記憶體競技場(memory arenas)、能乾淨對應到 Rust 結構體的 MemoryLayout 描述,以及能將原生符號轉成 MethodHandle 的 Linker,讓您像呼叫普通 Java 方法一樣使用。jextract 工具甚至能從 C header 自動產生大部分樣板程式碼,省去自己手寫描述符的麻煩。再也不用在到期日當天下午兩點跟原生指標玩俄羅斯輪盤。

以下是最簡化的示範。首先是 Rust 端,編譯成 cdylib:

// Cargo.toml
// [lib]
// crate-type = ["cdylib"]

#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
    // 雖然只是簡單範例,但足以證明互通性可行
    // 而且不會讓 JVM 又發作
    a + b
}

用一般方式建置:

cargo build --release
# 會產生 target/release/libtrading_rust.so(或 .dylib / .dll)

接著是使用最終版 FFM API 的 Java 端:

import java.lang.foreign.*;
import static java.lang.foreign.ValueLayout.*;

public class RustInteropDemo {
    public static void main(String[] args) throws Throwable {
        // 載入 Rust 共享物件(請依您的環境調整路徑)
        System.load("/path/to/target/release/libtrading_rust.so");

        Linker linker = Linker.nativeLinker();
        SymbolLookup lookup = SymbolLookup.loaderLookup();

        MemorySegment addSymbol = lookup.find("rust_add")
            .orElseThrow(() -> new RuntimeException("Symbol not found"));

        FunctionDescriptor descriptor = FunctionDescriptor.of(
            JAVA_INT, JAVA_INT, JAVA_INT
        );

        MethodHandle addHandle = linker.downcallHandle(addSymbol, descriptor);

        int result = (int) addHandle.invokeExact(40, 2);
        System.out.println("Rust says 40 + 2 = " + result);
    }
}

就這麼簡單。沒有 JNI 膠水程式碼,沒有脆弱的 Makefile。兩邊的編譯器都會確保您不會出錯。

為了展示對交易工作負載真正重要的零複製功能,以下是一個更有趣的範例:Rust 函式直接計算 Java 傳來的陣列 VWAP,而無需複製資料:

#[no_mangle]
pub extern "C" fn calculate_vwap(
    prices: *const f64,
    volumes: *const f64,
    len: usize,
) -> f64 {
    // 正式環境應加入適當驗證或使用更安全的 wrapper。
    // 這裡是互通邊界,請視為潛水艇的氣閘。
    let mut sum_pv = 0.0;
    let mut sum_v = 0.0;

    unsafe {
        for i in 0..len {
            let p = *prices.add(i);
            let v = *volumes.add(i);
            sum_pv += p * v;
            sum_v += v;
        }
    }

    if sum_v > 0.0 { sum_pv / sum_v } else { 0.0 }
}

在 Java 端,您使用 Arena 配置堆外記憶體、填入資料後傳遞位址。Rust 直接讀取,沒有 GC 暫停,也不用先把整個市場資料快照複製到堆積中。

真正重要的效能表現

回報立竿見影而且相當可觀。Rust 實作通常能提供相當 Java 系統兩到五倍的吞吐量,即使市場真正失控,仍能維持嚴格的尾端延遲保證。特別是高頻交易部門特別喜愛這種確定性的次微秒回應,因為穩定的 50 微秒優勢就能透過更精準的訂單執行轉化為可觀的額外收入。

不再有抖動導致您的 Value-at-Risk 模型或壓力測試失效。基準測試甚至顯示 Rust 的 FIX 引擎和限價委託簿在吞吐量上比最佳化過的 C++ 還快 12% 至 15%,同時 99.9 百分位延遲依然表現優異。差異來自零成本抽象、不會與借用檢查器衝突的無鎖資料結構,以及完全沒有會隨時決定暫停世界的 GC 執行緒。

您的效能分析工具不再在交易量暴增時像聖誕樹一樣狂亮。過去在背景執行的風險計算,現在能在下一筆市場資料到達前就完成。這類改善會直接反映在損益表上,而不只是投影片裡的數字。

更便宜的營運成本(也更環保)

這不只是原始速度的問題。Rust 二進位檔的 CPU 與記憶體消耗比 Java 版本少 30% 至 60%。這代表您可以縮減雲端執行個體,在相同工作負載下將基礎設施支出降低 40% 以上。

節省效果會連鎖發生:更少的伺服器、移出的部分不再需要 JVM 授權費用,以及更低的電費,讓 ESG 團隊眉開眼笑。能源使用曲線更接近 C 而非 Java,因此您可以更早汰換舊設備、整合工作負載,在不費力的情況下滿足中央銀行的可持續發展要求。真實的金融科技遷移案例顯示,單靠基礎設施節省就能在九個月內回收成本。

當下一輪營運韌性問卷寄來時,您可以拿出實際數據,而不是「我們多加了 heap 然後祈禱最好」。

「Rust 太難」的迷思已經死亡

最棒的是,過去「Rust 對企業團隊來說太難」的藉口,已被人工智慧悄悄終結。現代大型語言模型工具能直接產生通過 Clippy 和編譯器的生產級 Rust 程式碼,而多代理工作流程則能封閉迴路處理架構樣板、記憶體安全與最佳化。

資深工程師不再需要跟借用檢查器搏鬥,可以專心處理領域邏輯。試點團隊回報,從想法到安全可部署二進位檔的速度提升三到四倍。過去的高風險高投入轉型,現在變成高報酬的下午專案。借用檢查器成為您那位雖然非常固執、但最終總是正確的同事,堅決不讓您把 use-after-free 漏洞送上生產環境。

仍然宣稱 Rust 太難的團隊,通常是還沒用最新工具試過的人。試過的人,都不會再回頭。

隨處部署 ─ 邊緣、裝置,或兩者皆可

一旦 Rust 站穩腳跟,部署選擇就會變得更有趣。將相同程式碼編譯成 WASM,部署到 Cloudflare Workers 或 Fastly,就能實現低於 10 毫秒的邊緣執行,用於詐欺偵測或外匯報價,比集中式架構減少高達 70% 的來回時間。

或者直接推送到裝置:交易終端機、行動應用程式、支付硬體或 IoT 閘道,本地處理能讓敏感資料留在裝置上,並大幅降低延遲。跨平台一致性意味著無論是在資料中心伺服器還是交易員的筆電上,核心函式庫的行為都完全相同。同一個 crate 既能加速您的撮合引擎,也能在交易室的平板電腦上執行交易前檢查。

是時候行動了

對於仍然依賴傳統 Java 或較舊 C++ 堆疊的機構來說,不斷上升的成本、無法預測的暫停、監管壓力以及人才戰爭,正逐漸成為沉重負擔。維持現狀已不再是安全的選擇,而是昂貴的選擇。

針對您最在意延遲或成本的工作負載,委託一個針對性的概念驗證。讓具備 AI 輔助的團隊處理繁重工作。實際測量吞吐量、尾端延遲、執行個體大小與耗電量的差異。因為您不是在替換整個系統,只是加速那些造成痛點的部分,所以合規文件比全面重寫輕鬆許多。

擁抱這種混合路徑並非瘋狂的架構賭注,而是一項戰略上的必然選擇。它能帶來更優異的效能、更低的成本、更佳的永續性與長期的韌性,同時讓您繼續保留已經投入的 Java 資產。

您的股東會注意到利潤率的改善。監管機構會看到更穩定的尾端延遲。交易大廳不會再抱怨系統又變慢了。而您將成為那個終於不再假裝 JVM 會自己好起來的人。

這不是一場革命,只是懂得在維持系統運作的同時,使用正確的工具來完成工作。