

如果你對訊息或流處理系統感興趣,那你肯定聽說過 Kafka。而且很可能,你也見過無數號稱“比 Kafka 更強”的解決方案。
這說明了兩件事:首先,Kafka 由於其強大的通用性,越來越多企業將其納入基礎設施中(說明市場在快速增長);其次,許多使用者在使用 Kafka 的過程中仍然面臨不小的挑戰,尤其是在如今這個雲計算時代(意味著有許多痛點亟待解決)。
當你把 Apache Kafka 部署到雲上時,它的 replica factor 會導致 Leader 節點將接收到的資料傳送給位於不同可用區(Availability Zone,AZ)內的 Follower 節點。與計算和儲存成本相比,跨 AZ 的資料傳輸成本一開始可能並不明顯;但根據 Confluent 的觀察,這部分傳輸成本居然可以佔到總賬單的 50% 以上(後文會詳細介紹)。
在我之前釋出的一篇關於 WarpStream [1] 的文章中,我們發現 WarpStream 透過“劫持”服務發現機制,讓客戶端始終連線到同一個可用區內的 Broker,從而規避了跨 AZ 的傳輸費用。而這背後的關鍵在於 WarpStream 對 Kafka 協議的重寫。
本週,我們將深入探討 AutoMQ —— 一個 100% 相容 Kafka 的替代方案,看看它是如何幫助使用者顯著降低跨 AZ 資料傳輸成本的。AutoMQ 的設計理念是:在雲環境下高效執行 Kafka,核心方式是保留 Kafka 協議棧(即複用 Kafka 程式碼),並重寫底層儲存架構,透過引入 WAL(預寫日誌)機制將資料高效解除安裝至物件儲存。
不久前,我寫過一篇關於 AutoMQ 的詳細文章,你可以檢視這篇文章 [2]。
本文將按以下結構展開:首先,我們會回顧 Confluent 對 Apache Kafka 的觀察;接著介紹 AutoMQ 的整體架構;最後,我們將揭示 AutoMQ 如何幫助使用者降低資料傳輸成本。
為了更方便地說明原理,文中將使用 AWS 上的服務(如 S3 或 EBS)來類比 AutoMQ 的功能模組。
Apache Kafka 最初是在 LinkedIn 開發的,用於應對該公司對日誌處理的高強度需求。Kafka 的設計深度契合 LinkedIn 的執行環境,工程師們透過充分利用頁面快取(Page Cache)和磁碟的順序訪問模式對其進行了最佳化。這種方式既能實現極高的吞吐量,又能保持系統架構的簡潔,因為大多數與儲存相關的任務由作業系統自動處理。
Kafka 依賴副本機制(Replication)來保證資料的永續性。當 Message 被寫入 Leader 分割槽時,必須同步複製到 Follower 分割槽。Kafka 最初運行於 LinkedIn 自建的資料中心環境中,在那種場景下,基礎設施團隊在 Leader 向不同資料中心的 Follower 複製 Message 時,並不需要考慮網路傳輸成本。
然而,當用戶將 Kafka 部署到雲上時,情況發生了變化。為了保證高可用性,Leader 節點需要將資料複製到位於不同可用區(Availability Zone,簡稱 AZ)中的 Follower 節點,以應對某個 AZ 宕機時的資料恢復需求。但在雲上,跨 AZ 的資料傳輸是需要額外付費的。根據 Confluent 的觀察,當用戶自建和管理 Apache Kafka 時,僅由於副本同步帶來的跨 AZ 資料傳輸成本,可能會佔據基礎設施總成本的 50% 以上,這一數字令人驚訝。

Confluent,“掌握 Kafka 基礎設施成本指南(2023)”
下面用一組資料來幫助理解這一現象:設想一個 Kafka 叢集包含三個 Broker,分別部署在三個不同的可用區內。如果某個 AZ 中的 Broker 發生故障,叢集仍可依賴另外兩個 Follower 繼續提供服務。一個負載均衡良好的叢集會將 Partition 的 Leader 分佈在三個 AZ 中,這意味著 Producer 大約有三分之二的時間會向其他 AZ 中的 Leader 寫入資料。

一旦 Leader 接收到 Message,它會將資料複製到其他可用區(AZ)中的 Broker,以確保高資料可靠性。這一過程會產生是原始生產請求兩倍的跨 AZ 流量。
簡而言之,Apache Kafka 的多 AZ 部署架構將至少產生(2/3 + 2)倍的跨 AZ 單價流量成本(以 AWS 為例,跨 AZ 資料傳輸為 $0.01/GB,進出流量分別收費)。
下面的計算不包含 Consumer 側產生的跨 AZ 成本。
假設使用三臺 r6i.large(2 核心,16GB 記憶體)配置的 Broker,可提供約 30MiB/s 的寫入吞吐量,那麼 Apache Kafka 每月產生的跨 AZ 流量成本如下:
30 × 60 × 60 × 24 × 30 ÷ 1024 × (2/3 + 2) × 0.02 ≈ $4050
而虛擬機器(VM)的成本僅為:
3 × 0.126 美元 / 小時(r6i.large 單價)× 24 × 30 = $272(僅為跨 AZ 成本的 6.7%)
接下來的部分將介紹 AutoMQ 如何幫助使用者降低跨 AZ 成本在,此之前,我們先簡要回顧一下 AutoMQ。

AutoMQ 的目標是在不犧牲效能的前提下,將所有 Message 寫入 Object Storage (物件儲存),從而提升 Kafka 的執行效率與靈活性。
為實現這一目標,AutoMQ 複用了 Apache Kafka 的計算與協議程式碼,並引入共享儲存架構以取代 Kafka Broker 的本地磁碟。從宏觀角度看,AutoMQ 的 Broker 首先將 Message 寫入記憶體快取(Memory Cache)。為了確保永續性,在將資料非同步寫入 Object Storage 之前,必須先寫入 Write-Ahead Log(WAL)儲存。
WAL 是一種僅追加的磁碟結構,常用於故障恢復與事務恢復。在資料庫系統中,變更內容會優先寫入該結構,再被真正寫入資料庫。
AutoMQ 使用堆外快取記憶體層來處理所有 Message 的讀寫操作,提供即時效能體驗。EBS 裝置在 AutoMQ 中充當 WAL。當 Broker 接收 Message 時,它先將資料寫入記憶體快取,並在持久化至 WAL 後才返回確認響應。EBS 同時也用於 Broker 故障後的資料恢復。
所有 AutoMQ 的資料都會被儲存在物件儲存中,如 AWS S3 或 Google GCS。Broker 會將日誌快取中的資料非同步寫入物件儲存。在元資料管理方面,AutoMQ 利用了 Kafka 的草稿模式(Draft Mode)。
AutoMQ 的 WAL 一大優勢是其高度靈活性,使用者可以根據自身業務場景選擇不同的儲存方案。例如,若未來 AWS 推出更高階的磁碟裝置,使用者即可無縫切換至新方案,以進一步提升 AutoMQ 的效能。

在下一節中,我們將探討 AutoMQ 如何在使用 S3 作為 WAL 時減少跨 AZ(Availability Zone,區域內設計上與其他 AZ 災難隔離的獨立位置)成本近 100% 的解決方案。
當使用 EBS WAL 時,雖然無法完全消除跨可用區(cross-AZ)資料傳輸成本,但由於資料直接儲存在 S3 而無需在 Broker 之間複製,AutoMQ 仍能大幅降低網路開銷。不過,當生產者(Producer)向 Leader Partition 傳送訊息時,仍會產生跨可用區流量費用。
AutoMQ 提出了一種創新方案——採用 S3 作為 WAL,從而徹底消除跨可用區資料傳輸成本。與先寫入 EBS 再同步至 S3 的傳統方式不同,S3 WAL 允許 Broker 直接將資料寫入 S3,並確保生產者僅將訊息傳送至同一可用區(AZ)內的 Broker。

在 Kafka 中,Producer 會先向 Bootstrap Servers 傳送元資料請求,以獲取包括 Partition Leader Broker 資訊在內的叢集元資料,隨後才正式傳送 Message。寫入操作始終由 Leader Partition 處理——客戶端生產資料時,只會與目標 Topic Partition 的 Leader 進行通訊。
在 Kafka 中,所有寫入操作(Write)都必須透過 Leader 完成。
在 AutoMQ 中使用 S3 WAL 時,情況就不同了。假設這樣一個場景:Producer 位於 AZ1,而分割槽 P2 的 Leader(B2)位於 AZ2,同時 AZ1 中還執行著 Broker B1。讓我們來看看這種架構下 Message 的完整生產路徑。
-
當 Producer 需要向 P2 寫入資料時,首先會向 Bootstrap Brokers 叢集傳送元資料請求。關鍵的是,Producer 必須在請求中攜帶其所在的可用區資訊(本例中為 AZ1)

在 Kafka 中,Producer 發起元資料請求後,可能會獲取到與其不在同一可用區(AZ)的 Broker B2 資訊,從而導致跨 AZ 通訊成本,而 AutoMQ 的設計目標正是要規避這一問題。
-
在 AutoMQ 端,透過一致性雜湊演算法(Consistent Hash Algorithm)將 Broker 對映到不同 AZ。例如,假設 AutoMQ 將 AZ2 中的 B2 對映到 AZ1 中的 B1。由於 AutoMQ 知道生產者 Pr1 位於 AZ1(基於元資料請求),因此將返回 B1 的資訊作為響應。如果生產者與 B2 位於同一 AZ,則返回 B2 的資訊。核心思想是確保生產者始終與同一 AZ 中的 Broker 通訊,從而有效避免跨 AZ 通訊。

-
當 Producer 收到 B1 的資訊後(請注意,該 Broker 並非目標分割槽的負責節點),就會開始向 B1 傳送訊息。
-
B1 會先將訊息快取在記憶體中,當資料量達到 8MB 或經過 250ms 後,就會將緩衝資料作為臨時檔案寫入物件儲存。

-
最精妙的部分來了:當訊息成功寫入 S3 後,B1 會向實際的分割槽 Leader(B2)發起 RPC 呼叫,通知臨時資料的位置資訊(這會導致不同 AZ 間的 Broker 產生少量跨區流量)。

-
接著 B2 會讀取這些臨時資料,並將其追加到目標分割槽 P2 中。待 B2 完成資料寫入後,會先響應 B1,最終由 B1 向 Producer 傳送確認回執。

以下是一個圖示,來幫助理解整個過程:

這種方案雖然能完全消除跨可用區(AZ)的資料傳輸成本,但客戶需要部署比使用 EBS WAL 時更多的虛擬機器例項(Broker)。原因與雲環境中虛擬機器和網路吞吐量的限制有關。相較於 EBS WAL,該方案需要從 S3 讀取額外資料,這會佔用虛擬機器的網路頻寬。換言之,S3 WAL 需要透過增加 VM 數量來應對提升的網路吞吐需求,從而確保其讀寫效能與 EBS WAL 保持同等水平。
在消費路徑(Consume Path)方面,AutoMQ 的處理流程與 Kafka 幾乎完全一致。得益於 100% 的 Kafka 相容性,AutoMQ 消費者( Consumer )能夠直接利用 Kafka 的 Rack-awareness 特性,確保始終從同一 AZ 內的 Broker 拉取資料。
關於 AutoMQ 如何幫助消費者避免跨 AZ 成本,還有一個關鍵因素是其內部自平衡機制(Self-balancing Mechanism)。該機制包含內建的 Rack-aware 分割槽排程功能,可以自動將分割槽均衡分配到多個 AZ 的 Broker 上。
雖然 Apache Kafka 本身支援 Rack-aware 機制,但僅靠這一特性並不能完全消除跨 AZ 流量。要徹底避免跨 AZ 流量成本,Kafka 需要確保分割槽在擴縮容、遷移等所有操作過程中都保持 AZ 間的均衡分佈。AutoMQ 透過其自平衡機制自動為使用者管理這些任務,這不僅確保了流量的平衡,系統在故障時可以自我恢復,而且極大地降低了跨 AZ 流量成本。
後續我將專門介紹 AutoMQ 的自平衡機制實現原理。
使用者可以根據不同場景選擇最適合的 WAL 解決方案。在延遲敏感型場景中(如反欺詐、金融交易或即時資料分析),EBS WAL 是更優選擇;而對於延遲要求不高的用例(如日誌收集或可觀測資料攝取),S3 WAL 能顯著降低成本。
從上述分析可見,WAL 實現在 AutoMQ 中起著關鍵作用。其 WAL 採用可插拔設計,這意味著當出現更先進的雲端儲存方案(如近期推出的 S3 Express One Zone)時,使用者可輕鬆將其整合到 WAL 中。這種設計使 AutoMQ 能充分發揮新興雲端儲存方案的優勢,適配多樣化使用者場景。透過 WAL 抽象層,AutoMQ 可快速獲得不同雲端儲存介質的特性收益,這正是 AutoMQ 所倡導的 “ One for All ” 理念。
在本文中,我們瞭解到,當用戶在雲上執行 Apache Kafka 時,跨可用區(AZ)成本可能佔據雲賬單的很大一部分。這些成本主要來自兩個因素:Producer 向不同 AZ 中的 Leader 傳送流量,以及需要在 Brokers 之間複製資料。
接下來,我們探討了 AutoMQ 是如何應對這一挑戰的:它允許 Producer 將訊息傳送至同一可用區內的 Broker,資料以批次形式寫入 S3,隨後由對應的分割槽 Leader 拉取並追加至目標分割槽。透過這種方式,AutoMQ 幾乎完全消除了跨 AZ 成本(僅在 Broker 之間發起 RPC 請求時仍會產生少量跨區流量)。
感謝您的閱讀,我們下篇文章再見!
參考資料
[1] I spent 8 hours researching WarpStream
[2] How do we run Kafka 100% on the object storage?
[3] With the help of Kaiming Wan, Director of Solutions Architect & Lead Evangelist @ AutoMQ
[4] AutoMQ official documentation
[5] AutoMQ blog
