《新程式設計師》雜誌|李鵬輝談開源雲原生訊息流系統

ApachePulsar發表於2022-02-15

編者薦語:

雲原生的誕生是為了解決傳統應用在架構、故障處理、系統迭代等方面的問題,而開源則為企業打造雲原生的架構貢獻了中堅力量。本文作者在全身心投入開源以及每日參與雲原生的過程中,對開源行業和雲原生流系統解決方案有了不一樣的思考與實踐。

以下文章來源於CSDN ,作者李鵬輝
本文出自《新程式設計師·雲原生和全面數字化實踐》。 作者李鵬輝,Apache Pulsar PMC 成員,StreamNative 首席工程師。責編 CSDN 唐小引。

隨著業務與環境的變化,雲原生的趨勢越來越明顯。現在正是企業從雲端計算向雲原生轉型的時代,雲原生理念經過幾年落地實踐的打磨已經得到了企業的廣泛認可,雲上應用管理更是成為企業數字化轉型的必選項。可以說,現在的開發者,或正在使用基於雲原生技術架構衍生的產品和工具,或正是這些產品和工具的開發者。

雲原生成為基礎戰略

那麼,什麼是雲原生?每個人都有不同的解釋。我認為,首先,雲原生就是為了在雲上執行而開發的應用,是對於企業持續快速、可靠、規模化地交付業務的解決方案。雲原生的幾個關鍵詞,如容器化、持續交付、DevOps、微服務等無一不是在詮釋其作為解決方案的特性與能力,而 Kubernetes 更以其開創性的宣告式 API 和調節器模式,奠定了雲原生的基礎。

其次,雲原生是一種戰略。雲原生的誕生是為了解決傳統應用在架構、故障處理、系統迭代等方面存在的問題。從傳統應用到雲,與其說是一次技術升級,不如說將其視為戰略轉型。企業上雲面臨應用開發、系統架構、企業組織架構,甚至商業產品的全面整合,是否加入雲原生大潮一次是將從方方面面影響企業長期發展的戰略性決策。

搭配開源底色的雲原生

近幾年誕生的與架構相關的開源專案大部分採用雲原生架構設計,開源為企業打造雲原生的架構貢獻了中堅力量。

開源技術與生態值得信任,雲可以給使用者帶來好的伸縮性,降低資源浪費。雲原生和開源的關係也可以從以 CNCF 為主的開源基金會持續推進雲原生的發展中略窺一二。許多開源專案本身就是為雲原生架構而生的,這是使用者上雲會優先考慮的基礎軟體特點。

以 Apache 軟體基金會為例,它是一箇中立的開源軟體孵化和治理平臺。Apache 軟體基金會在長期的開源治理中,總結出的 Apache 之道(Apache Way)被大家奉為圭臬,其中“社群大於程式碼”廣為流傳,即沒有社群的專案是難以長久的。一個社群和程式碼保持高活躍度的開源專案,經過全世界開發者在多種場景的打磨,可以不斷完善、頻繁地升級迭代,並誕生豐富的生態以滿足不同的使用者需求。雲原生大潮與當前開源大環境兩種因素疊加,就會使那些伴隨技術環境不斷升級的優秀技術推陳出新、脫穎而出,不適應時代的技術會漸漸落後,甚至被淘汰。正如我之前所說,雲原生是戰略性決策,企業的戰略性決策必定會首選最先進、最可靠的技術。

為雲而生的訊息流資料系統

前文講述了雲原生環境下開源的重要性,那麼一個雲原生的開源專案需要如何去設計、規劃和演進?雲原生時代的企業數字化轉型應如何選擇訊息和流系統?在本文中,我將以自己全身心投入的開源雲原生訊息和流資料系統 Apache Pulsar 的設計和規劃為例進行剖析。希望能夠為大家提供參考思路,併為尋求訊息和流資料系統解決方案帶來啟發。

回顧歷史:訊息與流的雙軌制

訊息佇列通常用於構建核心業務應用程式服務,流則通常用於構建包括資料管道等在內的實時資料服務。訊息佇列擁有比流更長的歷史,也就是開發者們所熟悉的訊息中介軟體,它側重在通訊行業,常見的系統有 RabbitMQ 和 ActiveMQ。相對來說,流系統是一個新概念,多用於移動和處理大量資料的場景,如日誌資料、點選事件等運營資料就是以流的形式展示的,常見的流系統有 Apache Kafka 和 AWS Kinesis。

由於之前的技術原因,人們把訊息和流分為兩種模型分別對待。企業需要搭建多種不同的系統來支援這兩種業務場景(見圖 1),由此造成基礎架構存在大量“雙軌制”現象,導致資料隔離、資料孤島,資料無法形成順暢流轉,治理難度大大提升,架構複雜度和運維成本也都居高不下。

圖片

圖 1 企業搭建不同的系統支援業務場景導致的“雙軌制”

基於此,我們亟須一個整合訊息佇列和流語義的統一實時資料基礎設施,Apache Pulsar 由此而生。訊息在 Apache Pulsar 主題上儲存一次,但可以通過不同訂閱模型,以不同的方式進行消費(見圖 2),這樣就解決了傳統訊息和流“雙軌制”造成的大量問題。

圖片

圖 2 Apache Pulsar 整合訊息佇列與流語義

實現天然雲原生的關鍵要素

上文提到,雲原生時代帶給開發者的是能夠快速擴縮容、降低資源浪費,加速業務推進落地。有了類似 Apache Pulsar 這種天然雲原生的訊息和流資料基礎設施,開發者可以更好地聚焦在應用程式和微服務開發,而不是把時間浪費在維護複雜的基礎系統上。

為什麼說 Apache Puslar 是“天然雲原生”?這與在當初設計原型的底層架構有關。儲存計算分離、分層分片的雲原生架構,極大地減輕了使用者在訊息系統中遇到的擴充套件和運維困難,能在雲平臺以更低成本給使用者提供優質服務,能夠很好地滿足雲原生時代訊息系統和流資料系統的需求。

生物學有一個結論,叫“結構與功能相適應”。從單細胞原生生物到哺乳動物,其生命結構越來越複雜,具備的功能也越來越高階。基礎系統同理,“架構與功能相適用”體現在 Apache Pulsar 上有這樣幾點:

  • 儲存計算分離架構可保障高可擴充套件性,可以充分發揮雲的彈性優勢。
  • 跨地域複製,可以滿足跨雲資料多備的需求。
  • 分層儲存,可充分利用如 AWS S3 等的雲原生儲存,有效降低資料儲存成本。
  • 輕量化函式計算框架 Pulsar Functions,類似於 AWS Lambda 平臺,將 FaaS 引入 Pulsar。而 Function Mesh 是一種 Kubernetes Operator,助力使用者在 Kubernetes 中原生使用 Pulsar Functions 和聯結器,充分發揮 Kubernetes 資源分配、彈性伸縮、靈活排程等特性。

基礎架構:儲存計算分離、分層分片

上文說到,Pulsar 在誕生之初就採用了雲原生的設計,即儲存計算分離的架構,儲存層基於 Apache 軟體基金會開源專案 BookKeeper。BookKeeper 是一個高一致性、分散式只追加(Append-only)的日誌抽象,與訊息系統和流資料場景類似,新的訊息不斷追加,剛好應用於訊息和流資料領域。

Pulsar 架構中資料服務和資料儲存是單獨的兩層(見圖 3),資料服務層由無狀態的 Broker 節點組成,資料儲存層則由 Bookie 節點組成,服務層和儲存層的每個節點對等。Broker 僅負責訊息的服務支援,不儲存資料,這為服務層和儲存層提供了獨立的擴縮容能力和高可用能力,大幅減少了服務不可用時間。BookKeeper 中的對等儲存節點,可以保證多個備份被併發訪問,也保證了即使儲存中只有一份資料可用,也可以對外提供服務。

圖片

圖 3 Pulsar 架構

在這種分層架構中,服務層和儲存層都能夠獨立擴充套件,提供靈活的彈性擴容,特別是在彈性環境(如雲和容器)中能自動擴縮容,動態適應流量峰值。同時,顯著降低叢集擴充套件和升級的複雜性,提高系統的可用性和可管理性。此外,這種設計對容器也非常友好。

Pulsar 將主題分割槽按照更小的分片粒度來儲存(見圖 4)。這些分片被均勻打散,將會分佈在儲存層的 Bookie 節點上。這種以分片為中心的資料儲存方式,將主題分割槽作為一個邏輯概念,分為多個較小的分片,並均勻分佈和儲存在儲存層中。這樣的設計可以帶來更好的效能、更靈活的擴充套件性和更高的可用性。

圖片

圖 4 分片儲存模型

從圖 5 可見,相比大多數訊息佇列或流系統(包括 Apache Kafka)均採用單體架構,其訊息處理和訊息持久化(如果提供了的話)都在叢集內的同一個節點上。此類架構設計適合在小型環境部署,當大規模使用時,傳統訊息佇列或流系統就會面臨效能、可伸縮性和靈活性方面的問題。隨著網路頻寬的提升、儲存延遲的顯著降低,儲存計算分離的架構優勢變得更加明顯。

圖片

圖 5 傳統單體架構 vs 儲存計算分層架構

讀寫區別

接著上述內容,我們來看一下訊息的寫入、讀取等方面的區別體現在哪裡。

首先看寫入。圖 6 左側是單體架構的應用,資料寫入 leader,leader 將資料複製到其他 follower,這是典型的儲存計算不分離的架構設計。在圖 6 右側則是儲存計算分離的應用,資料寫入 Broker,Broker 並行地往多個儲存節點上寫。假如要求 3 個副本,在選擇強一致性、低延遲時兩個副本返回才算成功。如果 Broker 有 leader 的角色,就會受限於 leader 所在機器的資源情況,因為 leader 返回,我們才能確認訊息成功寫入。

圖片

圖 6 單體架構與分層架構寫入對比

在右側對等的分層架構中,三個中任意兩個節點在寫入後返回即為成功寫入。我們在 AWS 上進行效能測試時發現,兩種結構在刷盤時的延遲也會有幾毫秒的差距:在單機系統中落在 leader 上的 topic 會有延遲,而在分層架構中受到延遲影響較小。

在實時資料處理中,實時讀取佔據了 90% 的場景(見圖 7)。在分層架構中,實時讀取可以直接通過 Broker 的 topic 尾部快取進行,不需要接觸儲存節點,能夠在很大程度上提升資料讀取的效率和實時性。

圖片

圖 7 單體架構與分層架構讀取實時資料對比

架構也導致了讀取歷史資料時的區別。從圖 8 可見,在單體架構中,回放訊息時直接找到 leader,從磁碟上讀取訊息。在儲存計算分離的架構上,需要將資料載入到 Broker 再返回客戶端,以此保證資料讀取的順序性。當讀取資料對順序性沒有嚴格要求時,Apache Pulsar 支援同時並行從多個儲存節點讀取資料段,即使是讀取一個 topic 的資料也可以利用多臺儲存節點的資源提升讀取的吞吐量,Pulsar SQL 也是利用這種方式來讀取的。

圖片

圖 8 單體架構與分層架構讀取歷史資料對比

IO 隔離

BookKeeper 內部做了很好的資料寫入和讀取的 IO 隔離。BookKeeper 可以指定兩類儲存裝置,圖 9 左側是 Journal 盤存放 writeheadlog,右側才是真正儲存資料的地方。即使在讀取歷史資料時,也會盡可能地保證寫入的延遲不會受到影響。

圖片

圖 9 BookKeeper 的 IO 隔離

如果利用雲平臺的資源,Pulsar 的 IO 隔離可以讓使用者選擇不同的資源型別。由於 Journal 盤並不需要存放大量的資料,很多雲使用者會根據自己的需求配置來達到低成本、高服務質量的目的,如 Journal 盤使用低儲存空間、高吞吐低延遲的資源,資料盤選擇對應吞吐可以存放大量資料的裝置。

擴縮容

儲存計算分離允許 Broker 和 BookKeeper 分別進行擴縮容,下面為大家介紹擴縮容 topic 的過程。假設 n 個 topic 分佈在不同的 Broker 上,新的 Broker 加入能夠在 1s 內進行 topic ownership 的轉移,可視為無狀態的 topic 組的轉移。這樣,部分 topic 可以快速地轉移至新的 Broker。

對於儲存節點來說,多個資料分片散佈在不同的 BookKeeper 節點上,擴容時即新加入一個 BookKeeper,並且這種行為不會導致歷史資料的複製。每一個 topic 在經歷一段時間的資料寫入後,會進行分片切換,即切換到下一個資料分片。在切換時會重新選擇 Bookies 放置資料,由此達到逐漸平衡。如果有 BookKeeper 節點掛掉,BookKeeper 會自動補齊副本數,在此過程中,topic 不會受到影響。

跨雲資料多備

Pulsar 支援跨雲資料多備(見圖 10),允許組成跨機房叢集來進行資料的雙向同步。很多國外使用者在不同的雲廠商部署跨雲叢集,當有一個叢集出現問題時,可以快速切換到另外的叢集。非同步複製只會產生細微的資料同步缺口,但可以獲得更高的服務質量,同時訂閱的狀態也可以在叢集間同步。

圖片

圖 10 跨雲資料多備

進入無伺服器架構時代

Pulsar Functions 與 Function Mesh 讓 Pulsar 跨入了無伺服器架構時代。Pulsar Functions 是一個輕量級的計算框架,主要是為了提供一個部署和運維都能非常簡單的平臺。Pulsar Functions 主打輕量、簡單,可用於處理簡單的 ETL 作業(提取、轉化、載入)、實時聚合、事件路由等,基本可以覆蓋 90%以上的流處理場景。Pulsar Functions 借鑑了無伺服器架構(Serverless)和函式即服務(FaaS)理念,可以讓資料得到“就近”處理,讓價值得到即時挖掘(見圖 11)。

圖片

圖 11 單條 Pulsar Function 訊息流轉

Pulsar Functions 只是單個應用函式,為了讓多個函式關聯在一起,組合完成資料處理目標,誕生了 Function Mesh(已開源)。Function Mesh 同樣採用無伺服器架構,它也是一種 Kubernetes Operator,有了它,開發者就可以在 Kubernetes 上原生使用 Pulsar Functions 和各種 Pulsar 聯結器,充分發揮 Kubernetes 資源分配、彈性伸縮、靈活排程等特性。例如,Function Mesh 依賴 Kubernetes 的排程能力,確保 Functions 的故障恢復能力,並且可以在任意時間適當排程 Functions。

Function Mesh 主要由 Kubernetes Operator 和 Function Runner 兩個元件組成。Kubernetes Operator 監測 Function Mesh CRD、建立 Kubernetes 資源(即 StatefulSet),從而在 Kubernetes 執行 Function、聯結器和 Mesh。Function Runner 負責呼叫 Function 和聯結器邏輯,處理從輸入流中接收的事件,並將處理結果傳送到輸出流。目前,Function Runner 基於 Pulsar Functions Runner 實現。

當使用者建立 Function Mesh CRD 時(見圖 12),Function Mesh 控制器從 Kubernetes API 伺服器接收已提交的 CRD,然後處理 CRD 並生成相應的 Kubernetes 資源。例如,Function Mesh 控制器在處理 Function CRD 時,會建立 StatefulSet,它的每個 Pod 都會啟動一個 Runner 來呼叫對應的 Function。

圖片

圖 12 Function Mesh 處理 CRD 過程

Function Mesh API 基於現有 Kubernetes API 實現,因此 Function Mesh 資源與其他 Kubernetes 原生資源相容,叢集管理員可以使用現有 Kubernetes 工具管理 Function Mesh 資源。Function Mesh 採用 Kubernetes Custom Resource Definition(CRD),叢集管理員可以通過 CRD 自定義資源,開發事件流應用程式。

使用者可以使用 kubectl CLI 工具將 CRD 直接提交到 Kubernetes 叢集,而無須使用 pulsar-admin CLI 工具向 Pulsar 叢集傳送 Function 請求。Function Mesh 控制器監測 CRD 並建立 Kubernetes 資源,執行自定義的 Function、Source、Sink 或 Mesh。這種方法的優勢在於 Kubernetes 直接儲存並管理 Function 後設資料和執行狀態,從而避免在 Pulsar 現有方案中可能存在的後設資料與執行狀態不一致的問題。

結語

在本文中,我分享了自己在雲原生環境下,對於開源行業的思考和雲原生流平臺解決方案的技術實踐。作為一名全身心投入的開源人,我很高興看到近幾年有越來越多的人認可開源理念併成為開源開發者與貢獻者,開源行業正在蓬勃發展。我希望能和無數的開發者一樣,在開源道路上一往無前,助力更多企業加速雲原生和數字化程式。

作者簡介

李鵬輝:Apache 軟體基金會頂級專案 Apache Pulsar PMC 成員和 Committer,目前就職於 StreamNative 公司擔任首席架構師。長期以來,其工作領域都與訊息系統、微服務和 Apache Pulsar 息息相關,曾於2019年推動Pulsar在智聯招聘的落地,構建內部統一訊息服務,之後加入Apache Pulsar 商業化公司 StreamNative,完成個人身份從一名開源專案使用者到開源專案開發者的轉變。他和他的團隊在 StreamNative 負責支援海量規模訊息場景使用者落地Apache Pulsar。


關注公眾號「Apache Pulsar」,獲取乾貨與動態

加入 Apache Pulsar 中文交流群 ??

相關文章