Categories
程式開發

我們為什麼從Kafka遷移至Pulsar?


最近,StreamSQL 在 Kafka 上構建了平台,但幾經實踐,研發團隊認為 Kafka 並非最合適的工具。本文將闡述該團隊用 Kafka 構建的解決方案,以及決定遷移到 Pulsar 的原因。

在今天,Apache Kafka 幾乎是事件流的同義詞。事件流是我們平台的核心部分,最近,我們將 Kafka 替換成了 Pulsar。我們已經與客戶當面談過這個問題,也在會議上討論過。前不久,Apache Pulsar 社區的一個朋友建議我寫一篇文章,分享我們的經驗和轉換的原因。

我們在 Kafka 上構建了平台,並且發現自己已經寫了大量的代碼來使系統按照我們的意願來運行。我們認為,Kafka 並非適合這項工作的工具。這一結論顯然對於很多用例來說,並不都正確,但即使這樣,使用 Kafaka 而不是 Pulsar 仍然是有意義的。我將在本文闡述我們用 Kafka 構建的解決方案,以及講述決定遷移到 Pulsar 的原因。

問題陳述

StreamSQL 是什麼?

image

StreamSQL 是一個圍繞事件源構建的數據存儲系統。 StreamSQL 由三個組件組成:事件存儲、轉換和物化狀態。事件存儲是發送到我們系統的每個域事件不可篡改的賬本。我們使用類似於 Cassandra、Redis 和 CockroachDB 的 API 為物化狀態提供服務。 Transformation (轉換)是將事件映射到狀態的純函數。根據 Transformation,我們接收到的每個事件都被處理並應用到物化狀態。

StreamSQL 在所有數據中追溯性地運行新的 Transformation。最終狀態是整個事件流的真實物化。此外,你還可以通過回滾和回放事件來生成一個“虛擬”狀態。虛擬狀態可用於訓練和驗證機器學習模型,也可以用於調試目的(如用於前端開發的 Redux)。

要求

系統需要能夠執行以下操作:

  • 將每個域事件永久存儲在系統中;

  • 通過保證對每個傳入的事件只處理一次,以保持物化狀態的一致性;

  • 能夠按照我們接收到的相同順序對所有歷史事件進行 Transformation;

  • 回滾並回放事件賬本,並在該點物化視圖。

最初的基於 Kafka 解決方案

image

最初的基於 Kafka 解決方案,由一組拼接在一起的大數據工具組成。系統將過去的事件存儲在 S3 中,並用 Spark 對它們進行處理。對於流數據,它使用 Kafka 和 Flink。要保持事件和物化視圖的一致性,需要在每個系統之間進行複雜的協調。

無限存儲每個域事件

image

每個域事件都將通過 Kafaka 進入系統,然後 Kafaka 會將其保存到 S3 中。這就使得我們能夠存儲大量很少使用的數據,並且具有高持久性和低成本。

我們曾嘗試在流上使用 Kafaka 的無限保留,但是發現它不僅成本昂貴,而且難以維護。在更大的主題(Topic)上,我們開始看到性能下降和不穩定的延遲的現象。由於此時我們已經幾乎完全遷移到 Pulsar 上,因此沒有進一步研究原因。

從批數據引導物化視圖

image

我們通過按順序處理每個事件來物化視圖。我們使用 Spark 來處理存儲在 S3 的大部分歷史數據。如果我們可以在這種情況發生時將事件暫停,事情就會變得簡單了。在這種情況下,我們可以讀取所有 S3 數據,然後切換到處理主題開頭的 Kafaka。實際上,從 Kafka 持久化到 S3 的事件之間有一個延遲,在將大型批集群交換為較小的流處理集群之間還存在另一個延遲。由於我們不能錯過任何事件的處理,因此,我們使用 Spark 在 S3 中處理盡可能多的事件,然後讓它返回最後一個事件的 ID。由於我們已經將 Kafka 配置為保留最近幾週的數據,所以我們可以將 Kafaka 的其餘事件回填。

從 Kafaka 回填

image

Spark 能夠處理過去的大多數事件,但它並不能讓我們了解最新的狀態。為了處理最後一組過去的事件,我們已經配置了 Kafaka 集群,以保留最後兩週確認的事件。我們運行一個 Flink 作業來繼續 Spark 啟動的 SQL Transformation。我們將 Flink 指向 Kafaka 中的第一個事件,並讓它通讀一遍,什麼也不做,直到它到達 Spark 停止的 messageID 為止。從那時起,它將繼續更新物化視圖,直到它到達流的頭部。最後,它通知 Transformermation API,物化視圖是最新的,可以使用。

更新傳入事件

image

一旦啟動物化視圖,StreamSQL 就必須保持物化視圖是最新的。在這一點上,這個問題是微不足道的。 Kafaka 將每個傳入事件直接傳遞給 Flink,然後 Flink 執行必要的更新。此時,Transformermation API 和 Spark 處於空閒狀態。但是,我們仍然將每個傳入的事件保存在 S3 中,以防用戶更新或創建 Transformation。

多租戶、回滾和回放、錯誤處理等

我們協調 Flink 和 Kafaka 一​​起工作,保存物化視圖的快照。通過適當的協調,我們可以實現無縫的回滾和回放功能。要對這一過程進行闡述,需要專門寫一篇博文(我們希望在不久的將來會撰寫)。

在本文中,我們也不會討論如何擴展 Flink 和 Kafaka 集群、如何處理服務故障,或者如何在所有這些不同的服務之間實現安全的多租戶(提示:每個解決方案都有不同的答案)。

為什麼是 Pulsar?

Pulsar 的構建是為了永久存儲事件,而不是在系統之間傳輸事件。此外,Pulsar 是在 Yahoo! 為在全球範圍內開發各種產品的團隊服務之上構建的。它本身就支持地理分佈和多租戶。 Pulsar 執行複雜的部署變得很容易,如為某些租戶保留專用服務器。我們盡可能利用這些特性。這使得我們可以將大部分的自定義邏輯交給 Pulsar 去處理。

S3 中的分層存儲

image

StreamSQL 用戶可以隨時創建新的物化視圖。這些視圖必須是所有事件的投影。因此每個 Transformation 都按順序處理每個歷史事件。在基於 Kafka 的解決方案中,我們將所有已確認的事件流傳輸到 S3 或 GCS。然後,Spark 中的批處理管道處理這些事件。整個系統需要我們協調事件流、批處理存儲、批處理計算、流計算和狀態存儲。在現實世界中,協調這些系統很容易出錯,而且成本高昂,且難以自動化。

如果我們可以將事件存儲配置為永久保存事件,那麼就可以將批處理和流管道合併在一起。 Pulsar 和 Kafka 都可以這麼做,但是,Kafka 沒有分層存儲。這意味著所有事件都必須保存在 Kafka 節點的磁盤上。事件賬本單調地增加,因此我們必須不斷地添加存儲空間。我們很少讀取大多數歷史事件,因此,我們昂貴的磁盤存儲大部分都處於休眠狀態。

另一方面,Apache Pulsar 具有內置的分層存儲。 Pulsar 將每個事件日誌分寫成段,並將不活動的段卸載(offloads)到 S3。這意味著只需對 Kafka 進行簡單的配置更改,即可獲得無限的、廉價的存儲空間。我們無需不斷地擴大集群的規模,就可以合併批處理和流管道。

我們可以將 Pulsar 配置為在主題達到特定大小時卸載事件,也可以手動運行。這使我們能夠靈活地設置正確的卸載策略來平衡成本和速度。我們正在構建機器學習模型,以使我們的卸載策略適合每個主題的特定需求。

獨立的計算和存儲擴展

image

我們的事件數量和使用模式在一天之中和不同的用戶之間變化很大。每個用戶的不同使用模式會導致存儲量或計算使用量的增加。幸運的是,Pulsar 將它的 Broker 從存儲層分開了。

Pulsar 可以執行三種不同的操作:Tail write(尾部寫入)、Tail read(尾部讀取)和 Historical read(歷史讀取)。和 Kafka 一樣,Pulsar 的寫操作總是走到最後。對於 Pulsar 來說,一次寫操作有三個步驟:首先,Broker 接收請求,然後 Broker 將其寫入到 Bookkeeper,最後,它將請求緩存以供後續 Tail read。這意味著 Tail read 非常快,根本不會觸及存儲層。相比之下,Historical read 對存儲層的影響就非常大。

對於 Kafka 和 Pulsar 來說,增加存儲節點相對容易,但這是一項非常昂貴的操作。必須對數據進行洗牌(Shuffle)和復制,才能正確地平衡存儲節點。在 Kafka 的情況下,Broker 和存儲位於同一個節點上,因此任何擴展操作都很昂貴。與之相比,在 Pulsar,Broker 是無狀態的,而且很容易進行擴展,成本也低廉。這意味著 Tail read 並不會帶來嚴重的規模問題。我們可以根據當前 Historical read 和 Tail read 的使用模式來調整集群。

內置多租戶

image

Pulsar 在構建的時候,就內置了多租戶。在 Yahoo!,許多在不同地域分佈的、從事不同產品工作的團隊共享同一個 Pulsar 集群。該系統必須跟踪各種預算和各種服務級別協議。它有一個特性及,允許我們在同一個 Pulsar 集群上運行所有用戶,同時保持性能、可靠性和安全性。

每個 Pulsar 主題都屬於一個命名空間(Namespace),而每個命名空間都屬於一個租戶。每個 StreamSQL 賬戶都映射到一個租戶。租戶彼此安全隔離。用戶不可能接觸到其他用戶的數據流。

從性能的角度來看,命名空間提供了關於隔離的其他有趣的動態。我們可以將用戶的命名空間隔離到一組特定的 Broker 和存儲節點。這限制了單個用戶對整個系統的影響。同時,我們可以在 Broker 上設置自動減載,這樣單個客戶機中的峰值可以被更大的系統吸收。

積極響應的社區

image

Pulsar 社區的 Slack 頻道真的太棒了!我的大多數問題幾乎都能立即得到解答,還有一些聚會和 Pulsar 峰會,以及面對面的學習和網絡課程。我們知道,哪怕在最糟糕的情況下,我們也可以聯繫相關人員,即使是最小眾的問題也能得到幫助。社區給了我們繼續前進的信心。

基於 Pulsar 的解決方案

image

無限存儲每個域事件

Pulsar 允許我們將整個不可篡改的賬本存儲在 Pulsar 主題中。我們將其視為全部都在 Pulsar 中,但是,事情的幕後是 Pulsar 將事件卸載到 S3 中了。我們從使用事件賬本中得到了簡單性的好處,以及將事件放入 S3 的成本和維護優勢。這一切都比我們的 Kafka 系統表現得更好,而不需要我們保持任何復雜性。

從批數據引導物化視圖

Pulsar 架構融合了我們的流和批處理能力。這使我們能夠刪除 Spark 以及 Spark 和 Flink 之間的所有協調代碼。 Pulsar->Flink 連接器在批處理模式和流處理模式之間進行無縫切換。該架構的簡單性消除了基於 Kafka 的版本中存在的大量邊緣情況、錯誤處理和維護成本。

更新傳入事件

我們編寫一個作業來同時處理批數據和流數據。在我們沒有任何協調的情況下,Flink 只維護一次處理,並在批處理模式和流模式之間進行切換。

Pulsar 的缺點

集成方式

Pulsar 的歷史幾乎與 Kafka 一樣長,並在 Yahoo!的生產環境中得到了驗證。我們認為,Pulsar 的核心是穩定可靠的。集成是另外一個問題。有關集成問題的列表是永遠寫不完的。在大多數情況下,Pulsar 社區構建並維護其集成。例如,我們希望將 S3 設置為接收器,並了解到不存在任何開源版本的連接器。我們構建了自己的開源解決方案,以推動社區向前發展,但我們希望在未來能夠找到缺失的集成。

鑑於到目前為止,Pulsar 遠沒有 Kafka 那麼受歡迎,因此大部分 Pulsar 集成都是在 Pulsar 廠里中構建並維護的。例如,我們使用的 Flink 連接器在 Pulsar 倉庫中,但也有一個開放的 Apache Flink 票證,可以在它們那邊構建一個。除非 Pulsar 能夠成​​為主流,否則缺失的集成還會繼續存在。

缺乏公共案例研究

幾乎所有的 Pulsar 內容都是由託管的 Pulsar 提供商發布的,比如 Streamlio(由 Splunk 提供)、Stream Native 和 Kafkaesque 等。在大規模生產中使用 Pulsar,卻與 Pulsar 沒有商業聯繫的公司進行 Pulsar 案例研究少之又少。有很多大公司在生產中使用 Pulsar,但他們卻很少分享經驗。如果有公共案例研究的話,我們就可以找到竅門,避開陷阱,而不需要重新發明輪子。

相比之下,有關 Kafaka 的案例研究比比皆是。 Kafaka 是最著名的事件流平台,而且還在繼續積攢人氣,所以大多數撰寫數據平台的公司都會深入講述他們是如何使用 Kafaka 的。

基礎設施的責任

我們的 Pulsar 部署需要一個用於元數據的 Zookeeper 集群、一個用於存儲的 Bookkeeper 集群、一個 Broker 集群和一個 Proxy 集群。即使使用 AWS 和 Google Cloud 服務,這也是一個很大的維護責任。單是 Pulsar 就有大量的配置可能性,但是,當你查看底層時,它可能需要多個專業工程師來維護和優化。

下一步是什麼

Pulsar 函數

目前,我們使用 Flink 處理流事件並更新物化視圖。 Flink 不允許向集群添加新節點。相反,我們必須保存一個檢查點並以更大的規模重新啟動集群。通常,Pulsar 函數是在一個單獨的計算集群中運行的,我們可以動態調整它的規模。

Flink 的處理引擎更具表現力,更強大,但擴展起來要復雜得多。 Pulsar 很容易擴展,但限制更多。我們將很快就能夠對 Transformation 進行分類,並決定在哪裡運行,傾向於使用 Pulsar 函數。

流的有向無環圖

StreamSQL 目前並不允許 Transformation 使用物化視圖作為狀態。我們正在把這個系統建模成一個有向無環圖(Directed Acyclic Graph,DAG),就像 Airflow 一樣。與 Airflow 不同的是,依賴關係不能一步一步地運行,每個事件都必須經過整個有向無環圖。當每個事件通過有向無環圖,Pulsar 將使維護這一保證變得容易得多。

StreamSQL 正處於測試階段

StreamSQL 是一個基於事件源數據存儲。它基於我們的數據基礎設施,我們用它為我們的機器學習模型提供支持,該模型的最終用戶超過一億。我們已經限制了功能集,並開放了測試版,現在可供用戶測試。

原文鏈接:

https://streamsql.io/blog/from-apache-kafka-to-apache-pulsar