![]()
Kafka 社區(qū)對(duì)共享存儲(chǔ)的興趣由來已久:如果所有數(shù)據(jù)都放在 S3 這樣的共享存儲(chǔ)上,Broker 就不需要本地磁盤,副本復(fù)制可以省掉,跨 AZ 流量費(fèi)也隨之消失。但對(duì)象存儲(chǔ)的延遲一直讓這個(gè)想法停留在「理論上很美」的階段。AWS 最近發(fā)布的 S3 Files 改變了這個(gè)前提——它給 S3 加上了 NFS 文件系統(tǒng)接口,小文件讀取延遲做到了亞毫秒級(jí)。于是一個(gè)老問題以新的面貌回來了:Kafka 能不能直接跑在 S3 Files 上?
我們?cè)?AutoMQ 從 2023 年起就在解決這個(gè)問題——不是把 Kafka 搬到共享文件系統(tǒng)上,而是從存儲(chǔ)引擎層重新設(shè)計(jì),讓 Kafka 真正運(yùn)行在共享存儲(chǔ)架構(gòu)上。我們是這個(gè)領(lǐng)域最早探索用共享文件系統(tǒng)作為存儲(chǔ)后端的團(tuán)隊(duì),也是目前唯一做到生產(chǎn)級(jí)低延遲的 Diskless Kafka 實(shí)現(xiàn)。所以當(dāng) S3 Files 出現(xiàn)時(shí),我們自然要評(píng)估它的可能性——以及它的邊界在哪里。
S3 Files 是什么?
要回答「Kafka 能不能跑在 S3 Files 上」,先得理解 S3 Files 到底做了什么。它本質(zhì)上是 AWS 在 S3 之上加了一層基于 EFS(Elastic File System)的文件系統(tǒng)訪問面——你可以通過 NFS 協(xié)議把 S3 存儲(chǔ)桶掛載到 EC2 實(shí)例上,像操作本地文件一樣讀寫,而 S3 始終是數(shù)據(jù)的 Source of Truth。
![]()
圖片這層訪問面的核心設(shè)計(jì)圍繞一個(gè) 128 KB 的閾值。小于 128 KB 的文件在首次訪問時(shí)會(huì)被導(dǎo)入 EFS 高性能層,讀取延遲可以做到亞毫秒到個(gè)位數(shù)毫秒;128 KB 及以上的文件則繞過 EFS,通過本地代理直接從 S3 流式讀取。寫入方向上,所有數(shù)據(jù)都先落到 EFS 層,再由后臺(tái)異步批量同步回 S3。換句話說,S3 Files 的優(yōu)化重點(diǎn)是小文件的低延遲讀取,而不是讓所有數(shù)據(jù)都常駐在高性能層。
定價(jià)模型進(jìn)一步印證了這個(gè)定位。寫入按流量計(jì)費(fèi) $0.06/GB,最小計(jì)費(fèi) I/O 為 6 KiB,沒有預(yù)置容量選項(xiàng)。數(shù)據(jù)同步到 S3 后不會(huì)立刻從 EFS 淘汰,默認(rèn)駐留 30 天,期間你同時(shí)支付 EFS 高性能層存儲(chǔ)費(fèi)($0.30/GB- 月)和 S3 存儲(chǔ)費(fèi)用。對(duì)于讀多寫少的場(chǎng)景,這個(gè)定價(jià)是合理的。但對(duì)于持續(xù)高吞吐寫入的工作負(fù)載,寫入成本和 EFS 駐留費(fèi)用會(huì)快速累積。
共享存儲(chǔ)對(duì) Kafka 的吸引力
理解了 S3 Files 的能力邊界,再來看為什么大家想把 Kafka 構(gòu)建在上面。傳統(tǒng) Apache Kafka 是為專用服務(wù)器加本地磁盤設(shè)計(jì)的,這套架構(gòu)搬到云上會(huì)產(chǎn)生三個(gè)不斷疊加的成本問題。
最直接的是副本復(fù)制帶來的跨 AZ 流量費(fèi)。Kafka 通過 ISR(In-Sync Replicas)機(jī)制保證持久性,每條消息會(huì)被復(fù)制到兩到三個(gè) Broker。在多 AZ 部署中,這種復(fù)制產(chǎn)生大量跨 AZ 網(wǎng)絡(luò)流量——AWS 對(duì)跨 AZ 數(shù)據(jù)傳輸雙向收費(fèi),合計(jì) $0.02/GB。一個(gè)寫入吞吐 500 MB/s、副本因子為 3 的集群,兩個(gè) Follower 分布在不同 AZ,每秒產(chǎn)生約 1 GB 的跨 AZ 復(fù)制流量,僅這一項(xiàng)就超過 $50,000/ 月。
![]()
圖片副本復(fù)制還帶來了第二個(gè)問題:存算耦合。每個(gè) Broker 在本地磁盤上管理自己的數(shù)據(jù)副本,擴(kuò)展存儲(chǔ)就意味著加機(jī)器——即使你只需要更多磁盤空間。而且必須按峰值負(fù)載加上故障冗余來預(yù)留容量,大部分時(shí)間都在為閑置資源付費(fèi)。
存算耦合又進(jìn)一步放大了運(yùn)維復(fù)雜度。分區(qū)重分配需要在 Broker 之間物理搬遷數(shù)據(jù),大 Topic 可能耗時(shí)數(shù)小時(shí)。Broker 故障觸發(fā)漫長(zhǎng)的恢復(fù)流程。縮容比擴(kuò)容更難,因?yàn)槟愕孟劝褦?shù)據(jù)搬走。
如果所有數(shù)據(jù)都在 S3 這樣的共享存儲(chǔ)上,這三個(gè)問題可以一次性解決:S3 自帶 11 個(gè) 9 的持久性,不需要副本復(fù)制;Broker 變成無狀態(tài)計(jì)算節(jié)點(diǎn),秒級(jí)擴(kuò)縮容;跨 AZ 流量降到接近零。S3 Files 有 NFS 接口、有亞毫秒延遲,看起來正好是連接 Kafka 和共享存儲(chǔ)之間的橋梁。但真正嘗試搭建這座橋梁時(shí),會(huì)遇到幾個(gè)根本性的問題。
挑戰(zhàn):直接把 Kafka
跑在 S3 Files 上會(huì)怎樣?
![]()
持久性缺口
最符合直覺的做法是把副本因子設(shè)為 1——既然 S3 Files 提供了共享的持久化存儲(chǔ),一份數(shù)據(jù)就夠了。問題出在 Kafka 的寫入機(jī)制上。
Kafka 是一個(gè)異步 I/O 系統(tǒng)。Producer 發(fā)送消息并收到 ack 時(shí),數(shù)據(jù)還在操作系統(tǒng)的 Page Cache 里,并不一定已經(jīng)刷到底層存儲(chǔ)。這是 Kafka 高吞吐的設(shè)計(jì)基礎(chǔ)——它假設(shè)即使 Broker 在刷盤前崩潰,數(shù)據(jù)仍然安全地存在于 Follower 副本上。但在 replica=1 的 S3 Files 上,這張安全網(wǎng)消失了。Broker 崩潰意味著 Page Cache 中尚未持久化的數(shù)據(jù)直接丟失,S3 Files 的 11 個(gè) 9 持久性幫不上忙——數(shù)據(jù)根本還沒到達(dá)存儲(chǔ)層。
要堵住這個(gè)缺口,需要改變 Kafka 的寫入路徑:確保每條被確認(rèn)的消息在返回 ack 之前就已經(jīng)持久化。這不是調(diào)配置能解決的,這是存儲(chǔ)引擎層面的重新設(shè)計(jì)。
可用性耦合
持久性問題可以通過改造寫入路徑來解決,但 Kafka 的高可用機(jī)制帶來了另一個(gè)更深層的挑戰(zhàn)。
Kafka 的 HA 和多副本設(shè)計(jì)緊密耦合:Broker 故障時(shí),Controller 將 Follower 副本提升為新 Leader。這個(gè)機(jī)制的前提是存在 Follower——而 replica=1 意味著沒有 Follower 可以提升。你需要一套完全不同的故障轉(zhuǎn)移邏輯:讓新 Broker 直接從共享存儲(chǔ)讀取數(shù)據(jù)來接管分區(qū),而不依賴本地副本。Kafka 現(xiàn)有的 HA 設(shè)計(jì)天然阻止了它利用 S3 Files 內(nèi)置的可用性保障。
這同樣需要架構(gòu)層面的重新設(shè)計(jì)——不只是寫入路徑,還有整個(gè)故障恢復(fù)和分區(qū)所有權(quán)的管理方式。
延遲現(xiàn)實(shí)
即使解決了持久性和可用性問題,延遲仍然是一道坎。S3 Files 宣傳的亞毫秒延遲針對(duì)的是 EFS 高性能層上的小文件讀取,而 Kafka 的核心工作負(fù)載是高吞吐的持續(xù)順序?qū)懭搿@兩者的 I/O 模式完全不同。
社區(qū)已經(jīng)有人在 S3 Files 上跑過 Kafka benchmark,數(shù)據(jù)很說明問題:
![]()
圖片數(shù)據(jù)來源:https://www.linkedin.com/pulse/apache-kafka-meets-s3-files-jason-taylor-kxiae/
中位數(shù)和 P95 看起來還行——P95 只有 5-13ms,和原生 Kafka 差距不大。但從 P95 到 P99 出現(xiàn)了斷崖式跳躍:5ms 直接飆到 704ms,延遲放大了 140 倍。這意味著每一百次請(qǐng)求就有一次要等超過一秒。對(duì)于實(shí)時(shí)流處理場(chǎng)景——風(fēng)控、實(shí)時(shí)大屏、事件驅(qū)動(dòng)微服務(wù)——這種不可預(yù)測(cè)的尾延遲是不可接受的。S3 Files 并沒有徹底解決共享存儲(chǔ)的低延遲問題,相比本地磁盤上的 Kafka 仍然有明顯的延遲犧牲。
成本結(jié)構(gòu)
![]()
延遲之外,S3 Files 的定價(jià)模型對(duì) Kafka 也不友好。S3 Files 采用按流量計(jì)費(fèi)——寫入 $0.06/GB,小文件讀取 $0.03/GB,沒有預(yù)置容量選項(xiàng)。這和 S3 的按 API 請(qǐng)求次數(shù)計(jì)費(fèi)是完全不同的模型。Kafka 的工作負(fù)載特征是寫入和讀取都需要走高性能層:Producer 寫入的數(shù)據(jù)落到 EFS 高性能層,Consumer 做 Tailing Read(消費(fèi)最新數(shù)據(jù))也從高性能層讀取。兩端都按流量計(jì)費(fèi),成本隨吞吐量線性增長(zhǎng)。寫入端還有雙重流量費(fèi)——數(shù)據(jù)先寫入 EFS($0.06/GB),再由后臺(tái)同步回 S3($0.03/GB),Kafka 的所有數(shù)據(jù)都需要同步回 S3,這筆同步費(fèi)逃不掉。更隱蔽的是 EFS 高性能層的存儲(chǔ)駐留費(fèi):$0.30/GB- 月,是 S3 Standard 存儲(chǔ)費(fèi)的 13 倍,數(shù)據(jù)默認(rèn)駐留 30 天才淘汰。
算一筆具體的賬。一個(gè) 100 MB/s 持續(xù)寫入的集群,假設(shè)消費(fèi)端吞吐和寫入相當(dāng)(1x fan-out,即一個(gè) Consumer Group),每天寫入和讀取各約 8,400 GB(100 MB/s × 86,400 秒):
![]()
圖片這還是 1x fan-out 的保守估算。如果有多個(gè) Consumer Group(在 Kafka 場(chǎng)景中很常見),Tailing Read 的流量費(fèi)會(huì)成倍增長(zhǎng)。2x fan-out 下月成本就超過 $113,000,3x 超過 $120,000。而且這還沒算 S3 本身的存儲(chǔ)費(fèi)。S3 Files 的定價(jià)模型是為「讀多寫少、活躍工作集小」的場(chǎng)景設(shè)計(jì)的——Kafka 恰好相反:持續(xù)高吞吐寫入,所有數(shù)據(jù)都是「活躍」的,讀取端也是持續(xù)高吞吐。
這些挑戰(zhàn)加在一起意味著什么?
持久性缺口要求重新設(shè)計(jì)寫入路徑。可用性耦合要求重新設(shè)計(jì)故障轉(zhuǎn)移機(jī)制。延遲問題要求在對(duì)象存儲(chǔ)之前加一層高性能寫入緩沖。成本問題要求對(duì)小寫入進(jìn)行攢批優(yōu)化。把這四項(xiàng)加在一起,你實(shí)際上需要的是一個(gè)全新的 Kafka 存儲(chǔ)引擎——而這正是 AutoMQ 從 2023 年就在構(gòu)建的東西。
AutoMQ 已經(jīng)被驗(yàn)證的
Shared Storage 架構(gòu)
AutoMQ 的架構(gòu)分為兩層。S3 是主存儲(chǔ)層,所有數(shù)據(jù)最終都持久化在 S3 上——這是和 Tiered Storage 的根本區(qū)別。Tiered Storage 仍然把熱數(shù)據(jù)放在本地磁盤上,S3 只存冷數(shù)據(jù);而 AutoMQ 讓 S3 成為唯一的 Single Source of Truth,Broker 上沒有任何持久化狀態(tài)。
關(guān)于兩者的詳細(xì)對(duì)比,可以參考這篇文章:https://docs.automq.com/automq/what-is-automq/difference-with-tiered-storage
但直接把每條消息都寫到 S3 有兩個(gè)問題:S3 的寫入延遲太高,而且 S3 API 調(diào)用是按次計(jì)費(fèi)的——每條消息一次 PUT 請(qǐng)求,API 成本會(huì)隨消息數(shù)線性爆炸。這就是 WAL(Write-Ahead Log)層存在的意義。
WAL 是一塊固定大小的高性能存儲(chǔ)空間,充當(dāng) S3 前面的寫入緩沖。所有 Produce 請(qǐng)求先寫入 WAL,使用 Direct IO 繞過 page cache,在返回 ack 之前就保證數(shù)據(jù)持久化——這直接堵住了上面說的持久性缺口。然后 WAL 中的數(shù)據(jù)被異步壓縮、攢批,再批量上傳到 S3。這個(gè)攢批過程至關(guān)重要:不是每條消息一次 S3 PUT,而是每批數(shù)千條消息一次 PUT,S3 API 成本從隨消息數(shù)增長(zhǎng)變成了隨吞吐量增長(zhǎng),降低了一到兩個(gè)數(shù)量級(jí)。
![]()
WAL 帶來的另一個(gè)關(guān)鍵好處是讓用戶可以在延遲和成本之間做 trade-off。WAL 層是可插拔的,不同的云存儲(chǔ)后端對(duì)應(yīng)不同的延遲和成本特征:EBS/Regional EBS WAL 提供亞毫秒延遲,NFS WAL(AWS 上基于 FSx for NetApp ONTAP)提供平均 6ms、P99 約 13ms 的寫入延遲。Producer 的體驗(yàn)和原生 Kafka 沒有區(qū)別。
而且 WAL 的成本很低。它只需要一小塊固定大小的存儲(chǔ)空間——不是存全量數(shù)據(jù),只是一個(gè)循環(huán)寫入的緩沖區(qū)。對(duì)于大部分云存儲(chǔ)的定價(jià)模型來說,這非常友好:每月幾美元到幾十美元的 WAL 支出,就能換來低延遲持久化、S3 API 成本優(yōu)化、以及真正的無狀態(tài) Broker。
因?yàn)樗谐志没癄顟B(tài)都在 WAL 和 S3 中,Broker 是真正無狀態(tài)的。一個(gè) Broker 故障時(shí),另一個(gè) Broker 在秒級(jí)內(nèi)接管分區(qū)映射,不需要數(shù)據(jù)遷移,Zero RPO——這解決了可用性耦合的問題。
最終效果是 Kafka on S3 Files 所承諾的一切——零跨 AZ 流量、無副本復(fù)制、彈性無狀態(tài) Broker——但沒有持久性缺口、秒級(jí)尾延遲和高昂的流量成本。
S3 Files 作為 WAL
技術(shù)上可行,經(jīng)濟(jì)上還不成熟
既然 AutoMQ 的 WAL 層是可插拔的,S3 Files 能不能作為又一個(gè) WAL 后端?從架構(gòu)上看,答案是肯定的。S3 Files 提供 NFS 接口,底層基于 EFS 構(gòu)建——而 AutoMQ 的 NFS WAL 已經(jīng)支持 EFS 和 FSx for NetApp ONTAP 作為實(shí)現(xiàn),技術(shù)路徑是通的。
但當(dāng)前的定價(jià)模型讓這個(gè)方案的經(jīng)濟(jì)賬算不過來。Kafka 不是一個(gè)輕量級(jí)的應(yīng)用層服務(wù),它是數(shù)據(jù)密集型的基礎(chǔ)設(shè)施——AutoMQ 的一些生產(chǎn)客戶集群吞吐超過 1 GiB/s,7×24 小時(shí)不間斷寫入。在這個(gè)量級(jí)下,S3 Files 的純按量計(jì)費(fèi)模型會(huì)產(chǎn)生驚人的費(fèi)用。
以一個(gè)相對(duì)溫和的工作負(fù)載為例——寫入吞吐 100 MB/s、平均消息大小 4 KiB:
![]()
圖片100 MB/s 已經(jīng)是一個(gè)保守的數(shù)字了。如果換成 1 GiB/s 的生產(chǎn)集群,S3 Files 的月成本會(huì)突破百萬美元——流量費(fèi)和 EFS 存儲(chǔ)駐留費(fèi)都隨吞吐量線性增長(zhǎng)。核心問題在于 S3 Files 的定價(jià)模型是為「讀多寫少、活躍工作集小」的場(chǎng)景設(shè)計(jì)的,而 Kafka 恰好相反:持續(xù)高吞吐寫入,所有數(shù)據(jù)都是「活躍」的。S3 Files 作為 WAL 的開銷遠(yuǎn)高于直接使用 EFS,而延遲上并沒有優(yōu)勢(shì)。
不過云存儲(chǔ)的定價(jià)在持續(xù)演進(jìn)。如果 AWS 為 S3 Files 引入預(yù)置吞吐模型或降低最小計(jì)費(fèi) I/O,這筆賬可能很快就會(huì)變。AutoMQ 的架構(gòu)已經(jīng)為那一天做好了準(zhǔn)備。
一套架構(gòu),適配所有云存儲(chǔ)
S3 Files 的故事其實(shí)揭示了一個(gè)更大的趨勢(shì):云存儲(chǔ)在加速分化。AWS 在過去兩年推出了 S3 Express One Zone(個(gè)位數(shù)毫秒延遲的 S3)、S3 Files(NFS over S3)、以及對(duì) EFS 和 FSx for NetApp ONTAP 的持續(xù)改進(jìn)。GCP 和 Azure 也在各自的存儲(chǔ)服務(wù)上走著類似的路線。每種存儲(chǔ)服務(wù)針對(duì)不同的訪問模式、成本模型和持久性保障做了優(yōu)化。
![]()
圖片AutoMQ 的可插拔 WAL 架構(gòu)意味著我們不需要押注某一個(gè)贏家——每一次云存儲(chǔ)創(chuàng)新都會(huì)成為 WAL 后端菜單上的一個(gè)新選項(xiàng):
![]()
圖片用戶不需要被鎖定在某一種存儲(chǔ)方案上,而是可以根據(jù)自己的延遲要求和成本預(yù)算自由選擇——并且隨著需求變化或云定價(jià)演進(jìn)隨時(shí)切換。在 AWS 上,NFS WAL 已經(jīng)支持 EFS 和 FSx for NetApp ONTAP 兩種實(shí)現(xiàn);在 Azure 和 GCP 上,Regional EBS WAL 利用各自的多 AZ 塊存儲(chǔ)提供亞毫秒延遲。讓這一切成為可能的 WAL 抽象層,從第一天起就是這么設(shè)計(jì)的。
回到最初的問題
Kafka 構(gòu)建在 S3 Files 上,是個(gè)好主意嗎?如果說的是把原生 Kafka 直接掛載上去——不是。Kafka 的異步 I/O、基于副本的 HA、對(duì)本地存儲(chǔ)的假設(shè),這些設(shè)計(jì)決策會(huì)讓你回到原點(diǎn):還是要管副本、管故障轉(zhuǎn)移、管容量規(guī)劃。共享存儲(chǔ)就在那里,但 Kafka 的架構(gòu)用不上。
但 Kafka 向 Shared Storage 架構(gòu)演進(jìn)的方向是確定的——經(jīng)濟(jì)賬和運(yùn)維收益太有說服力了。AutoMQ 基于 WAL 的 Shared Storage 架構(gòu)已經(jīng)交付了這個(gè)承諾,而且每當(dāng)云存儲(chǔ)向前邁進(jìn)一步,可插拔的 WAL 層就把這次創(chuàng)新變成用戶的一個(gè)新選項(xiàng)。一套架構(gòu),適配所有云存儲(chǔ)。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.