“如果可以從零開始重新設計 Kafka,一個真正云原生的事件日志系統,它應該具備怎樣的特性?”你是否有想過這個問題。本文作者 Gunnar Morling 結合多年來在事件驅動應用、實時 ETL 和變更數據捕獲(CDC)領域使用 Kafka 的實踐經驗,梳理了一份理想版 Kafka.next 的特性清單,看看這個是你想要的嗎?
原文鏈接:https://www.morling.dev/blog/what-if-we-could-rebuild-kafka-from-scratch/
作者 | Gunnar Morling
責編 |蘇宓
出品 | CSDN(ID:CSDNnews)
以下為譯文:
這幾天,我花時間仔細研究了最近公布的KIP-1150(也叫“Diskless Kafka”,無盤 Kafka),還有 AutoMQ 發布的 Kafka 分支版本。這些新版本把 Apache Kafka 和對象存儲(比如 Amazon 的 S3)做了很深度的結合。簡單說,就是想讓 Kafka 在云環境中用起來更輕松,這些項目效仿了 WarpStream 提出的思路,主要目標是讓 Kafka 能根據需求更靈活地擴展或縮減資源(即彈性)、大幅降低使用成本,以及進一步為未來和“數據湖倉一體”(lakehouse)這樣的新型數據架構無縫整合打基礎。
這些探索讓我開始思考:如果今天從零開始,重新設計一個真正面向云原生的、高可靠的事件日志系統(可以叫它Kafka.next),那它應該具備哪些理想特性呢?
當然,計算和存儲分離、支持對象存儲這些是最基本的要求,但除此之外,還應該具備什么?
結合我這些年用 Kafka 構建事件驅動應用、做實時 ETL(實時抽取-轉換-加載數據流程)和變更數據捕獲(CDC,Change Data Capture)管道的經驗,下面是我個人希望能有的一些功能清單:
取消分區的概念
以前 Kafka 需要把數據分成很多“分區”,這樣才能把數據分散到各個服務器本地磁盤上,解決擴展性問題。但在云端,用上了像 S3 這樣的超大對象存儲后,就不再需要這種分區機制了。
雖然分區還能幫我們保證數據的“順序性”,但實際上從應用角度來看,這種順序性沒那么有用。一般來說,要么你希望整個主題(topic)里所有消息有全局順序,要么更常見的是同一個 key 的消息保持順序。
而分區導致的情況是,一些本來無關的消息,僅僅因為哈希碰巧算到同一個分區,就強行有了順序——這并沒有多大意義。所以,新系統里完全可以不再把“分區”暴露給用戶。
以 Key 為中心的數據訪問方式
與其像現在這樣按分區讀數據,我們更希望能直接、快速地訪問所有屬于同一個 key 的消息。
也就是說,不用粗略地掃整個主題或分區,而是有幾百萬條以實體為單位的小流(stream),每條小流對應一個 key。
這樣做有很多好處,包括只讀取你真正需要的數據,效率更高;消費者(消費者就是讀取消息的程序)數量可以根據實際需要動態調整,不再受限于預先固定的分區數;保證了同一個 key 的消息順序,非常適合做事件溯源(Event Sourcing)架構、基于 actor 或 agent 的系統;還能自然解決傳統分區里“堵頭”(head-of-line blocking)的問題。如果某條消息處理失敗,只影響它自己對應的 key,不會影響其他 key 的消息。
簡單說,就是每個 key 成了一個獨立的小系統,壞了也只影響自己,而不是連累一大片。
支持 Topic 層級結構
在像 Solace 這樣的系統里,可以把消息內容的一部分提升成一個有層次的路徑式主題名字(就像文件夾路徑一樣),比如 orders/usa/california。這樣,客戶端就可以根據模式(pattern)靈活訂閱自己想要的一部分消息,比如只訂閱美國加州的訂單流。而且服務器(broker)不需要解析完整消息,只需要看路徑就能決定怎么分發,非常高效。
并發控制機制
現在用 Kafka 做“最終數據存儲”的話有個問題:沒辦法防止寫入的數據是基于舊版本信息的。舉個例子:你看到賬戶余額是 100,想扣 10,但別人剛好在你之前扣了 90,這時你如果直接寫,會把余額弄錯。
如果有類似樂觀鎖(optimistic locking)的機制,比如基于 key 版本號的檢查,就能避免這種沖突。這樣,當一條消息成功提交時,可以保證它看到的是 key 的最新狀態,從而避免數據更新丟失。
Broker 端原生支持 Schema
現在 Kafka 把消息當成黑盒(二進制數組),完全不管里面是什么內容。這就導致:消費者(讀取方)要自己通過旁路機制(比如 Schema Registry)去搞清楚數據格式;如果有壞心眼的生產者(發送方)發了不符合格式的數據,Kafka 也攔不住;也因此,Kafka 的數據很難直接寫入像 Apache Iceberg 這種開源數據表格式。
如果 Kafka 能直接在服務器端支持 Schema,就能大大改善使用體驗,比如Kafka 本身就能提供標準的接口(比如 AsyncAPI)來描述消息結構;還能直接支持按列(columnar)存儲,為不同需求優化數據。
系統擴展性和可插拔性
很多成功的開源項目,比如 Postgres 和 Kubernetes,都有一個共同點:很容易擴展和定制。用戶可以通過標準接口添加自己的插件(而不是改核心代碼),實現自己的功能。
在 Kafka.next 中,這種可擴展性應該成為基礎設計,比如可以寫自定義的消息過濾器、消息轉換器;支持不同的存儲格式(比如按列存儲);可以通過插件添加限流、加密、或者讓 topic 直接和 Iceberg 表對接的能力。
簡單說,就是系統自己盡量少管死,留出空間讓用戶按需擴展。
同步提交回調
現在 Kafka 保證的是“最終一致性”,也就是說,生產者發完一條消息后,并不知道什么時候下游系統(比如數據庫)真正處理完了。有些場景下,我們希望當生產者收到確認時,就能確定下游已經同步好了。
如果能實現這種同步機制,Kafka 就能真正像一個有強一致性特性的數據庫來用了,比如可以實現“寫后立刻讀到”的體驗。
快照功能(Snapshotting)
目前 Kafka 支持“壓縮”(compaction)功能,也就是保留同一個 key 的最后一條記錄。如果每條記錄都包含了完整狀態,比如一條訂單記錄就包含了所有訂單信息,那這樣壓縮是沒問題的。但如果是部分更新,比如“訂單狀態從待支付改成已支付”,那就需要把所有變化都按順序應用一遍,才能恢復完整狀態。
隨著變化越來越多,恢復速度就會變得越來越慢。
如果 Kafka 支持內置的快照功能,就能在需要的時候把一系列變化總結成一個當前狀態的快照,后續更新基于這個快照繼續處理,舊記錄可以清理掉,大大提高效率。
多租戶支持(Multi-tenancy)
任何現代數據系統,從設計一開始就應該考慮多租戶場景。比如,為每個客戶快速創建隔離的環境,操作應該既便宜又迅速。同時,不同客戶之間在訪問權限、安全性、資源使用、計費等方面應該完全隔離,互不影響。
其實,這里提到的一些功能,有些系統已經實現了。例如,S2 支持了超大量小流(high cardinality streams)、Waltz 里有樂觀鎖(optimistic locking)、Apache Pulsar 做得很好的就是多租戶(multi-tenancy)。
但,要把這些特點全部集成在一個系統里——尤其是開源系統,目前我還沒見過。
回過頭來說,以上這些,只是我個人心目中理想版Kafka.next應該具備的能力。(當然,強調一下,這篇文章完全代表我個人觀點,和我供職的公司 Confluent 沒有官方關系。)這些想法,主要是基于我這些年看到大家用 Kafka 想做的各種應用場景和需求總結出來的。不過我相信,每個用過 Kafka 或類似平臺的人,心里應該也都有自己的一份清單。
最后,當然有個很重要的問題是:那這樣一個系統到底應該怎么設計呢?
關于這個,我今天就先不展開了。不過可以先透露一點:如果要真的實現上面這些功能,基于日志結構合并樹(Log-Structured Merge Tree,簡稱 LSM Tree)的設計,很可能是個不錯的選擇。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
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.