Aeron 框架初探

FunTester發表於2024-12-05

Aeron 是什麼

Aeron 是一款開源的高效能訊息傳遞框架,專為低延遲和高吞吐場景設計。它被廣泛應用於金融、遊戲、分散式系統等需要快速通訊的領域。Aeron 的核心優勢在於透過零複製技術和直接記憶體訪問,最大限度地降低訊息傳遞的延遲,同時利用高效的網路協議實現資料的可靠傳輸。

其架構包括媒體驅動器和客戶端 API,支援單播、廣播和程序間通訊。Aeron 還提供持久化模組(Aeron Archive),便於訊息流的儲存與回放,滿足日誌重放等需求。

Aeron 支援 Java、C++、C# 等多語言,適配多種場景,如分散式日誌複製、高頻交易等。開發者可靈活選擇嵌入式或獨立部署模式,以滿足不同應用需求。憑藉極低延遲、強穩定性和簡潔的程式設計模型,Aeron 成為高效能通訊領域的佼佼者,是構建實時系統的理想選擇。

Aeron 的優勢

選擇 Aeron 的理由在於其專注於極致效能和低延遲的最佳化。相比傳統訊息中介軟體如 Kafka 和 RabbitMQ,Aeron 的零複製技術和直接記憶體操作將延遲降至微秒級,滿足高頻交易、實時資料分發等對響應速度極為敏感的場景。此外,Aeron 透過靈活的單播、多播及程序間通訊模式,提供更簡單的部署方式和開發體驗,避免了傳統中介軟體依賴複雜分散式管理工具的麻煩。

與 Kafka 注重吞吐和持久化,RabbitMQ 強調功能豐富不同,Aeron 更傾向於實時性需求,專為高效能任務而生。它不僅能穩定處理高併發流量,還具備訊息回放功能,兼顧了效能與可靠性,成為構建實時應用的優選。

基礎概念

Aeron 架構組成

Media Driver:Media Driver 是 Aeron 的通訊核心,負責底層資料的傳輸處理,包括程序內(IPC)和網路間(UDP)的通訊操作。它利用直接記憶體和記憶體對映檔案,實現高效的訊息傳遞,同時支援單播和多播模式,滿足不同場景的需求。

Client API:Client API 是 Aeron 面向開發者的高階介面,簡化了訊息釋出和訂閱的操作流程。透過它,開發者可以輕鬆建立 Publication 和 Subscription,專注於業務邏輯,而無需處理複雜的底層實現。

Log Buffer:Log Buffer 是共享記憶體區域,用於儲存釋出的訊息資料,供訂閱者訪問。它基於環形緩衝區設計,確保高效的訊息寫入和讀取,同時支援流量控制和重傳功能。

核心術語

  • Publication 和 Subscription:Publication 是訊息的釋出端,負責將資料寫入 Log Buffer;Subscription 是訊息的訂閱端,從 Log Buffer 讀取資料,形成 Aeron 的釋出 - 訂閱模型核心。
  • Channel:Channel 是訊息通訊的介質,指定訊息的傳輸方式,例如程序內(IPC)或跨主機的網路通訊(UDP)。它是連線釋出者和訂閱者的橋樑。
  • Stream ID:Stream ID 用於標識同一 Channel 內的不同邏輯訊息流,允許多個獨立的資料流共用一個通訊通道,提高資源利用率。
  • Session ID:Session ID 用於區分同一 Stream ID 內不同釋出者的會話。即使多個釋出者共享一個邏輯流,每個會話的資料都能獨立追蹤。

    傳輸方式

  • IPC:IPC(程序間通訊)是 Aeron 的最快通訊模式,依託共享記憶體直接傳輸訊息,適合部署在同一主機內的高效能應用場景。

  • UDP:UDP 支援主機間的網路通訊,是 Aeron 的跨網路傳輸方式。它透過單播或多播傳送資料,保證了低延遲和高擴充套件性,適合分散式環境。

code 實踐

建立 MediaDriver

建立服務端比較簡單,如下:

// 建立並啟動不帶存檔功能的
MediaDriverMediaDriver mediaDriver = MediaDriver.launch();  
System.out.println("Aeron Archive Server is running...");

在我查詢資料的過程中,有一些教程會在這行程式碼後面加上無限休眠來保障 MediaDriver 的執行。在我實際測試當中,並不會發生程式碼執行完就終止的情況,可能是早期版本的設計差異導致,各位在使用當中可以以實際測試結果為準。

建立 Publisher

相對來說複雜一些,但是照著官方的教程還是比較容易寫個 Demo 出來的。PS:官方教程會將各個步驟單獨拿出來演示,並說明作用。沒有耐心的可以直接原始碼倉庫找 Demo。

import io.aeron.Aeron;  
import io.aeron.ConcurrentPublication;  
import io.aeron.driver.MediaDriver;  
import org.agrona.concurrent.IdleStrategy;  
import org.agrona.concurrent.SleepingIdleStrategy;  
import org.agrona.concurrent.UnsafeBuffer;  

public class ArchivePublisher {  

    public static void main(String[] args) throws InterruptedException {  
        // 建立並啟動不帶存檔功能的 MediaDriver        MediaDriver mediaDriver = MediaDriver.launch();  
        System.out.println("Aeron Archive Server is running...");  
        // 建立一個空閒策略,用於在沒有資料時進行空閒  
        IdleStrategy idleStrategy = new SleepingIdleStrategy();  
        // 建立Aeron上下文  
        Aeron.Context ctx = new Aeron.Context();  
        // 建立Aeron例項  
        Aeron aeron = Aeron.connect(ctx);  
        // 宣告 channel 和 streamId        String channel = "aeron:udp?endpoint=localhost:40123";  
        int streamId = 10;  
        ConcurrentPublication publication = aeron.addPublication(channel, streamId);// 建立獨佔釋出者,作用是確保只有一個釋出者,避免多個釋出者同時釋出資料  
        // 等待發布者連線  
        while (!publication.isConnected()) {  
            idleStrategy.idle();  
        }  
        System.out.println("Publication connected");  
        for (int i = 0; i < 10000; i++) {  
            Thread.sleep(1000);  
            String s = "Hello World! From SDET!" + i;  
            byte[] bytes = s.getBytes();  
            UnsafeBuffer buffer = new UnsafeBuffer(bytes);  
            while (publication.offer(buffer) < 0) {  
                idleStrategy.idle();  
            }  
            System.out.println("Published message: " + s);  
        }  
    }  

}

建立 Subscription

同上,建議大家去直接官方原始碼中獲取完成的 Demo。

import io.aeron.Aeron;  
import io.aeron.Subscription;  
import org.agrona.concurrent.BackoffIdleStrategy;  
import org.agrona.concurrent.IdleStrategy;  

public class AeronSubscription {  
    public static void main(String[] args) {  
        // 建立Aeron上下文  
        Aeron.Context aeronCtx = new Aeron.Context();  
        // 建立Aeron例項  
        Aeron aeron = Aeron.connect(aeronCtx);  
        // 建立訂閱,並指定channel和streamId  
        Subscription subscription = aeron.addSubscription("aeron:udp?endpoint=localhost:40123", 10);  
        // 建立空閒策略  
        IdleStrategy idleStrategy = new BackoffIdleStrategy();  
        while (true) {  
            // 從訂閱中獲取資料  
            int fragments = subscription.poll((buffer, offset, length, header) -> {  
                // 建立一個位元組陣列,用於存放資料  
                byte[] data = new byte[length];  
                buffer.getBytes(offset, data);// 將資料從buffer中讀取到data中  
                System.out.println(buffer);// 列印buffer  
                System.out.println(offset);// 列印offset  
                System.out.println(header.position());// 列印position  
                System.out.println(header.termId());// 列印termId  
                System.out.println(header.sessionId());// 列印sessionId  
                System.out.println("Received message: " + new String(data));  
                System.out.println("------------------------");  
            }, 10);  
            idleStrategy.idle(fragments);  
        }  
    }  
}

Aeron 效能為何這麼高

Aeron 的高效能得益於多個設計上的最佳化,特別是在記憶體管理、網路傳輸和延遲控制等方面。以下是其主要的效能優勢:

零複製記憶體管理

Aeron 的一個關鍵特性是採用了零複製 (Zero-Copy) 技術,特別是在資料傳輸和儲存中。資料透過直接在記憶體中傳輸,而不是進行昂貴的複製操作,避免了 CPU 和記憶體之間不必要的資料移動。透過 Direct Memory,Aeron 可以直接從使用者空間寫入到核心緩衝區,減少了資料複製和上下文切換的開銷。

高效的共享記憶體模型

Aeron 使用了 共享記憶體 (Shared Memory) 模型來進行程序間通訊。這種設計使得多個程序能夠直接讀寫共享的記憶體區域,而不需要經過傳統的作業系統緩衝區或磁碟檔案。這種方式顯著降低了延遲,提高了資料傳輸速度。對於同一臺機器上的程序間通訊(IPC),Aeron 透過共享記憶體提供幾乎為零的延遲。

面向流的架構

Aeron 將通訊設計成流(Stream)模型,透過 Stream ID 來標識不同的資料流。每個流都擁有獨立的緩衝區和流控制機制,這種設計提高了訊息的傳輸效率,並降低了多個流之間的相互干擾。每個流的訊息都能獨立處理,最佳化了吞吐量和併發效能。

低延遲網路協議

Aeron 支援 UDP 協議,允許在不同機器間進行快速資料傳輸。相較於基於 TCP 的傳統訊息中介軟體,UDP 更輕量,減少了協議棧中的處理步驟,進一步降低了延遲。同時,Aeron 內部實現了自己的 flow control 和 error recovery 機制,確保即使在高負載的情況下也能保證訊息的有序和可靠傳輸。

高效的傳輸機制

Aeron 最大程度地減少了上下文切換、記憶體分配和同步鎖等開銷。它透過使用單執行緒模型來減少多執行緒上下文切換帶來的開銷,同時利用現代硬體的多核架構進行高效的資料處理。

在 Aeron 中,釋出者(Publication)和訂閱者(Subscription)的設計使得訊息可以以高效的方式傳遞。在釋出和訂閱的過程中,Aeron 透過直接記憶體對映和環形緩衝區實現了低延遲的資料傳遞,不會像傳統的訊息中介軟體那樣存在大量的佇列或緩衝區複製。

FunTester 原創精華
  • 混沌工程、故障測試、Web 前端
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go
  • 白盒、工具、爬蟲、UI 自動化
  • 理論、感悟、影片
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援
暫無回覆。