比拼 Kafka, 大資料分析新秀 Pulsar 到底好在哪

首席資料師發表於2018-12-13

一年一度由世界知名科技媒體 InfoWorld 評選的 Bossie Awards 於 9 月 26 日公佈,本次 Bossie Awards 評選出了最佳資料庫與資料分析平臺獎、最佳軟體開發工具獎、最佳機器學習專案獎等多個獎項。在最佳開源資料庫與資料分析平臺獎中,之前曾連續兩年入選的 Kafka 意外滑鐵盧落選,取而代之的是新興專案 Pulsar。

近一年釋出了不少 Pulsar 的技術文章,我們經常被問到一個問題:Apache Pulsar 和 Apache Kafka 到底有什麼不同?今天,大家所期待的對比文終於來了!本文將詳述 Pulsar 和 Kafka 訊息模型之間的區別,以及 Pulsar 與 Kafka 在系統架構設計方面的差異。

在使用者選擇一個訊息系統時,訊息模型是使用者首先考慮的事情。訊息模型應涵蓋以下 3 個方面:

訊息消費——如何傳送和消費訊息;

訊息確認(ack)——如何確認訊息;

訊息儲存——訊息保留多長時間,觸發訊息刪除的原因以及怎樣刪除;

訊息消費模型

在實時流式架構中,訊息傳遞可以分為兩類:佇列(Queue)和流(Stream)。

佇列(Queue)模型

佇列模型主要是採用無序或者共享的方式來消費訊息。通過佇列模型,使用者可以建立多個消費者從單個管道中接收訊息;當一條訊息從佇列傳送出來後,多個消費者中的只有一個(任何一個都有可能)接收和消費這條訊息。訊息系統的具體實現決定了最終哪個消費者實際接收到訊息。這裡給大家推薦下我自己建立的大資料資料分享群834325294,這是大資料學習交流的地方,不管你是小白還是大牛,小編都歡迎,不定期分享乾貨,包括我整理的一份適合大資料零基礎學習大資料進階資料

佇列模型通常與無狀態應用程式一起結合使用。無狀態應用程式不關心排序,但它們確實需要能夠確認(ack)或刪除單條訊息,以及儘可能地擴充套件消費並行性的能力。典型的基於佇列模型的訊息系統包括 RabbitMQ 和 RocketMQ。

流式(Stream)模型

相比之下,流模型要求訊息的消費嚴格排序或獨佔訊息消費。對於一個管道,使用流式模型,始終只會有一個消費者使用和消費訊息。消費者按照訊息寫入管道的確切順序接收從管道傳送的訊息。

流模型通常與有狀態應用程式相關聯。有狀態的應用程式更加關注訊息的順序及其狀態。訊息的消費順序決定了有狀態應用程式的狀態。訊息的順序將影響應用程式處理邏輯的正確性。

在面向微服務或事件驅動的體系結構中,佇列模型和流模型都是必需的。

Pulsar 的訊息消費模型

Apache Pulsar 通過“訂閱”,抽象出了統一的: producer-topic-subscription-consumer 消費模型。Pulsar 的訊息模型既支援佇列模型,也支援流模型。

在 Pulsar 的訊息消費模型中,Topic 是用於傳送訊息的通道。每一個 Topic 對應著 Apache BookKeeper 中的一個分散式日誌。釋出者釋出的每條訊息只在 Topic 中儲存一次;儲存的過程中,BookKeeper 會將訊息複製儲存在多個儲存節點上;Topic 中的每條訊息,可以根據消費者的訂閱需求,多次被使用,每個訂閱對應一個消費者組(Consumer Group)。

主題(Topic)是消費訊息的真實來源。儘管訊息僅在主題(Topic)上儲存一次,但是使用者可以有不同的訂閱方式來消費這些訊息:

消費者被組合在一起以消費訊息,每個消費組是一個訂閱。

每個 Topic 可以有不同的消費組。

每組消費者都是對主題的一個訂閱。

每組消費者可以擁有自己不同的消費方式: 獨佔(Exclusive),故障切換(Failover)或共享(Share)。

Pulsar 通過這種模型,將佇列模型和流模型這兩種模型結合在了一起,提供了統一的 API 介面。 這種模型,既不會影響訊息系統的效能,也不會帶來額外的開銷,同時還為使用者提供了更多靈活性,方便使用者程式以最匹配模式來使用訊息系統。

獨佔訂閱(Stream 流模型)

顧名思義,獨佔訂閱中,在任何時間,一個消費者組(訂閱)中有且只有一個消費者來消費 Topic 中的訊息。下圖是獨佔訂閱的示例。在這個示例中有一個有訂閱 A 的活躍消費者 A-0,訊息 m0 到 m4 按順序傳送並由 A-0 消費。如果另一個消費者 A-1 想要附加到訂閱 A,則是不被允許的。

 

故障切換(Stream 流模型)

使用故障切換訂閱,多個消費者(Consumer)可以附加到同一訂閱。 但是,一個訂閱中的所有消費者,只會有一個消費者被選為該訂閱的主消費者。 其他消費者將被指定為故障轉移消費者。這裡給大家推薦下我自己建立的大資料資料分享群834325294,這是大資料學習交流的地方,不管你是小白還是大牛,小編都歡迎,不定期分享乾貨,包括我整理的一份適合大資料零基礎學習大資料進階資料

當主消費者斷開連線時,分割槽將被重新分配給其中一個故障轉移消費者,而新分配的消費者將成為新的主消費者。 發生這種情況時,所有未確認(ack)的訊息都將傳遞給新的主消費者。 這類似於 Apache Kafka 中的 Consumer partition rebalance。

下圖是故障切換訂閱的示例。 消費者 B-0 和 B-1 通過訂閱 B 訂閱消費訊息。B-0 是主消費者並接收所有訊息。 B-1 是故障轉移消費者,如果消費者 B-0 出現故障,它將接管消費。

 

共享訂閱(Queue 佇列模型)

使用共享訂閱,在同一個訂閱背後,使用者按照應用的需求掛載任意多的消費者。 訂閱中的所有訊息以迴圈分發形式傳送給訂閱背後的多個消費者,並且一個訊息僅傳遞給一個消費者。

當消費者斷開連線時,所有傳遞給它但是未被確認(ack)的訊息將被重新分配和組織,以便傳送給該訂閱上剩餘的剩餘消費者。

下圖是共享訂閱的示例。 消費者 C-1,C-2 和 C-3 都在同一主題上消費訊息。 每個消費者接收大約所有訊息的 1/3。

如果想提高消費的速度,使用者不需要不增加分割槽數量,只需要在同一個訂閱中新增更多的消費者。

三種訂閱模式的選擇

獨佔和故障切換訂閱,僅允許一個消費者來使用和消費每個對主題的訂閱。這兩種模式都按主題分割槽順序使用訊息。它們最適用於需要嚴格訊息順序的流(Stream)用例。

共享訂閱允許每個主題分割槽有多個消費者。同一訂閱中的每個消費者僅接收主題分割槽的一部分訊息。共享訂閱最適用於不需要保證訊息順序的佇列(Queue)的使用模式,並且可以按照需要任意擴充套件消費者的數量。

Pulsar 中的訂閱實際上與 Apache Kafka 中的 Consumer Group 的概念類似。建立訂閱的操作很輕量化,而且具有高度可擴充套件性,使用者可以根據應用的需要建立任意數量的訂閱。

對同一主題的不同訂閱,也可以採用不同的訂閱型別。比如使用者可以在同一主題上可以提供一個包含 3 個消費者的故障切換訂閱,同時也提供一個包含 20 個消費者的共享訂閱,並且可以在不改變分割槽數量的情況下,向共享訂閱新增更多的消費者。

下圖描繪了一個包含 3 個訂閱 A,B 和 C 的主題,並說明了訊息如何從生產者流向消費者。

 

除了統一訊息 API 之外,由於 Pulsar 主題分割槽實際上是儲存在 Apache BookKeeper 中,它還提供了一個讀取 API(Reader),類似於消費者 API(但 Reader 沒有遊標管理),以便使用者完全控制如何使用 Topic 中的訊息。

Pulsar 的訊息確認(ACK)

由於分散式系統的特性,當使用分散式訊息系統時,可能會發生故障。比如在消費者從訊息系統中的主題消費訊息的過程中,消費訊息的消費者和服務於主題分割槽的訊息代理(Broker)都可能發生錯誤。訊息確認(ACK)的目的就是保證當發生這樣的故障後,消費者能夠從上一次停止的地方恢復消費,保證既不會丟失訊息,也不會重複處理已經確認(ACK)的訊息。

在 Apache Kafka 中,恢復點通常稱為 Offset,更新恢復點的過程稱為訊息確認或提交 Offset。

在 Apache Pulsar 中,每個訂閱中都使用一個專門的資料結構–遊標(Cursor)來跟蹤訂閱中的每條訊息的確認(ACK)狀態。每當消費者在主題分割槽上確認訊息時,遊標都會更新。更新遊標可確保消費者不會再次收到訊息。

Apache Pulsar 提供兩種訊息確認方法,單條確認(Individual Ack)和累積確認(Cumulative Ack)。通過累積確認,消費者只需要確認它收到的最後一條訊息。主題分割槽中的所有訊息(包括)提供訊息 ID 將被標記為已確認,並且不會再次傳遞給消費者。累積確認與 Apache Kafka 中的 Offset 更新類似。

Apache Pulsar 可以支援訊息的單條確認,也就是選擇性確認。消費者可以單獨確認一條訊息。 被確認後的訊息將不會被重新傳遞。下圖說明了單條確認和累積確認的差異(灰色框中的訊息被確認並且不會被重新傳遞)。在圖的上半部分,它顯示了累計確認的一個例子,M12 之前的訊息被標記為 acked。在圖的下半部分,它顯示了單獨進行 acking 的示例。僅確認訊息 M7 和 M12 - 在消費者失敗的情況下,除了 M7 和 M12 之外,其他所有訊息將被重新傳送。

獨佔訂閱或故障切換訂閱的消費者能夠對訊息進行單條確認和累積確認;共享訂閱的消費者只允許對訊息進行單條確認。單條確認訊息的能力為處理消費者故障提供了更好的體驗。對於某些應用來說,處理一條訊息可能需要很長時間或者非常昂貴,防止重新傳送已經確認的訊息非常重要。

這個管理 Ack 的專門的資料結構–遊標(Cursor),由 Broker 來管理,利用 BookKeeper 的 Ledger 提供儲存,在後面的文章中我們會介紹更多的關於遊標(Cursor)的細節。

Apache Pulsar 提供了靈活的訊息消費訂閱型別和訊息確認方法,通過簡單的統一的 API,就可以支援各種訊息和流的使用場景。

Pulsar 的訊息保留(Retention)

在訊息被確認後,Pulsar 的 Broker 會更新對應的遊標。當 Topic 裡面中的一條訊息,被所有的訂閱都確認 ack 後,才能刪除這條訊息。Pulsar 還允許通過設定保留時間,將訊息保留更長時間,即使所有訂閱已經確認消費了它們。

下圖說明了如何在有 2 個訂閱的主題中保留訊息。訂閱 A 在 M6 和訂閱 B 已經消耗了 M10 之前的所有訊息之前已經消耗了所有訊息。這意味著 M6 之前的所有訊息(灰色框中)都可以安全刪除。訂閱 A 仍未使用 M6 和 M9 之間的訊息,無法刪除它們。如果主題配置了訊息保留期,則訊息 M0 到 M5 將在配置的時間段內保持不變,即使 A 和 B 已經確認消費了它們。

在訊息保留策略中,Pulsar 還支援訊息生存時間(TTL)。如果訊息未在配置的 TTL 時間段內被任何消費者使用,則訊息將自動標記為已確認。 訊息保留期訊息 TTL 之間的區別在於:訊息保留期作用於標記為已確認並設定為已刪除的訊息,而 TTL 作用於未 ack 的訊息。 上面的圖例中說明了 Pulsar 中的 TTL。 例如,如果訂閱 B 沒有活動消費者,則在配置的 TTL 時間段過後,訊息 M10 將自動標記為已確認,即使沒有消費者實際讀取該訊息。

Pulsar VS. Kafka

通過以上幾個方面,我們對 Pulsar 和 Kafka 在訊息模型方面的不同點進行一個總結。

模型概念

Kafka: Producer - topic - consumer group - consumer;

Pulsar:Producer - topic - subscription - consumer。

消費模式

Kafka: 主要集中在流(Stream)模式,對單個 partition 是獨佔消費,沒有共享(Queue)的消費模式;

Pulsar:提供了統一的訊息模型和 API。流(Stream)模式 – 獨佔和故障切換訂閱方式;佇列(Queue)模式 – 共享訂閱的方式。

訊息確認(Ack)

Kafka: 使用偏移 Offset;

Pulsar:使用專門的 Cursor 管理。累積確認和 Kafka 效果一樣;提供單條或選擇性確認。

訊息保留

Kafka:根據設定的保留期來刪除訊息。有可能訊息沒被消費,過期後被刪除。 不支援 TTL。

Pulsar:訊息只有被所有訂閱消費後才會刪除,不會丟失資料。也允許設定保留期,保留被消費的資料。支援 TTL。

對比總結

Apache Pulsar 將高效能的流(Apache Kafka 所追求的)和靈活的傳統佇列(RabbitMQ 所追求的)結合到一個統一的訊息模型和 API 中。 Pulsar 使用統一的 API 為使用者提供一個支援流和佇列的系統,且具有同樣的高效能。 應用程式可以將此統一的 API 用於高效能佇列和流式傳輸,而無需維護兩套系統:RabbitMQ 進行佇列處理,Kafka 進行流式處理。

系統架構和設計理念

Pulsar 的分層架構

Apache Pulsar 和其他訊息系統最根本的不同是採用分層架構。 Apache Pulsar 叢集由兩層組成:無狀態服務層,由一組接收和傳遞訊息的 Broker 組成;以及一個有狀態持久層,由一組名為 bookies 的 Apache BookKeeper 儲存節點組成,可持久化地儲存訊息。 下圖顯示了 Apache Pulsar 的典型部署。

 

在 Pulsar 客戶端中提供生產者和消費者(Producer & Consumer)介面,應用程式使用 Pulsar 客戶端連線到 Broker 來發布和消費訊息。

Pulsar 客戶端不直接與儲存層 Apache BookKeeper 互動。 客戶端也沒有直接的 BookKeeper 訪問許可權。這種隔離,為 Pulsar 實現安全的多租戶統一身份驗證模型提供了基礎。

Apache Pulsar 為客戶端提供多種語言的支援,包括 Java,C ++,Python,Go 和 Websockets。

Apache Pulsar 還提供了一組相容 Kafka 的 API,使用者可以通過簡單地更新依賴關係並將客戶端指向 Pulsar 叢集來遷移現有的 Kafka 應用程式,這樣現有的 Kafka 應用程式可以立即與 Apache Pulsar 一起使用,無需更改任何程式碼。

Broker 層:無狀態服務層

Broker 叢集在 Apache Pulsar 中形成無狀態服務層。服務層是“無狀態的”,因為 Broker 實際上並不在本地儲存任何訊息資料。有關 Pulsar 主題的訊息,都被儲存在分散式日誌儲存系統(Apache BookKeeper)中。我們將在下一節中更多地討論 BookKeeper。

每個主題分割槽(Topic Partition)由 Pulsar 分配給某個 Broker,該 Broker 稱為該主題分割槽的所有者。 Pulsar 生產者和消費者連線到主題分割槽的所有者 Broker,以向所有者代理髮送訊息並消費訊息。

如果一個 Broker 失敗,Pulsar 會自動將其擁有的主題分割槽移動到群集中剩餘的某一個可用 Broker 中。這裡要說的一件事是:由於 Broker 是無狀態的,當發生 Topic 的遷移時,Pulsar 只是將所有權從一個 Broker 轉移到另一個 Broker,在這個過程中,不會有任何資料複製發生。

下圖顯示了一個擁有 4 個 Broker 的 Pulsar 叢集,其中 4 個主題分割槽分佈在 4 個 Broker 中。每個 Broker 擁有併為一個主題分割槽提供訊息服務。

 

BookKeeper 層:持久化儲存層

Apache BookKeeper 是 Apache Pulsar 的持久化儲存層。 Apache Pulsar 中的每個主題分割槽本質上都是儲存在 Apache BookKeeper 中的分散式日誌。

每個分散式日誌又被分為 Segment 分段。 每個 Segment 分段作為 Apache BookKeeper 中的一個 Ledger,均勻分佈並儲存在 BookKeeper 群集中的多個 Bookie(Apache BookKeeper 的儲存節點)中。

Segment 的建立時機包括以下幾種:基於配置的 Segment 大小;基於配置的滾動時間;或者當 Segment 的所有者被切換。

通過 Segment 分段的方式,主題分割槽中的訊息可以均勻和平衡地分佈在群集中的所有 Bookie 中。 這意味著主題分割槽的大小不僅受一個節點容量的限制; 相反,它可以擴充套件到整個 BookKeeper 叢集的總容量。

下面的圖說明了一個分為 x 個 Segment 段的主題分割槽。 每個 Segment 段儲存 3 個副本。 所有 Segment 都分佈並儲存在 4 個 Bookie 中。

Segment 為中心的儲存

儲存服務的分層的架構 和 以 Segment 為中心的儲存 是 Apache Pulsar(使用 Apache BookKeeper)的兩個關鍵設計理念。 這兩個基礎為 Pulsar 提供了許多重要的好處:

無限制的主題分割槽儲存

即時擴充套件,無需資料遷移

無縫 Broker 故障恢復

無縫叢集擴充套件

無縫的儲存(Bookie)故障恢復

獨立的可擴充套件性

下面我們分別展開來看這幾個好處。

無限制的主題分割槽儲存

由於主題分割槽被分割成 Segment 並在 Apache BookKeeper 中以分散式方式儲存,因此主題分割槽的容量不受任何單一節點容量的限制。 相反,主題分割槽可以擴充套件到整個 BookKeeper 叢集的總容量,只需新增 Bookie 節點即可擴充套件叢集容量。 這是 Apache Pulsar 支援儲存無限大小的流資料,並能夠以高效,分散式方式處理資料的關鍵。 使用 Apache BookKeeper 的分散式日誌儲存,對於統一訊息服務和儲存至關重要。

即時擴充套件,無需資料遷移

由於訊息服務和訊息儲存分為兩層,因此將主題分割槽從一個 Broker 移動到另一個 Broker 幾乎可以瞬時內完成,而無需任何資料重新平衡(將資料從一個節點重新複製到另一個節點)。 這一特性對於高可用的許多方面至關重要,例如叢集擴充套件;對 Broker 和 Bookie 失敗的快速應對。 我將使用例子在下文更詳細地進行解釋。

無縫 Broker 故障恢復

下圖說明了 Pulsar 如何處理 Broker 失敗的示例。 在例子中 Broker 2 因某種原因(例如停電)而斷開。 Pulsar 檢測到 Broker 2 已關閉,並立即將 Topic1-Part2 的所有權從 Broker 2 轉移到 Broker 3。在 Pulsar 中資料儲存和資料服務分離,所以當代理 3 接管 Topic1-Part2 的所有權時,它不需要複製 Partiton 的資料。 如果有新資料到來,它立即附加並儲存為 Topic1-Part2 中的 Segment x + 1。 Segment x + 1 被分發並儲存在 Bookie1, 2 和 4 上。因為它不需要重新複製資料,所以所有權轉移立即發生而不會犧牲主題分割槽的可用性。

無縫叢集容量擴充套件

下圖說明了 Pulsar 如何處理叢集的容量擴充套件。 當 Broker 2 將訊息寫入 Topic1-Part2 的 Segment X 時,將 Bookie X 和 Bookie Y 新增到叢集中。 Broker 2 立即發現新加入的 Bookies X 和 Y。然後 Broker 將嘗試將 Segment X + 1 和 X + 2 的訊息儲存到新新增的 Bookie 中。 新增加的 Bookie 立刻被使用起來,流量立即增加,而不會重新複製任何資料。 除了機架感知和區域感知策略之外,Apache BookKeeper 還提供資源感知的放置策略,以確保流量在群集中的所有儲存節點之間保持平衡。

無縫的儲存(Bookie)故障恢復

下圖說明了 Pulsar(通過 Apache BookKeeper)如何處理 bookie 的磁碟故障。 這裡有一個磁碟故障導致儲存在 bookie 2 上的 Segment 4 被破壞。Apache BookKeeper 後臺會檢測到這個錯誤並進行復制修復。

Apache BookKeeper 中的副本修復是 Segment(甚至是 Entry)級別的多對多快速修復,這比重新複製整個主題分割槽要精細,只會複製必須的資料。 這意味著 Apache BookKeeper 可以從 bookie 3 和 bookie 4 讀取 Segment 4 中的訊息,並在 bookie 1 處修復 Segment 4。所有的副本修復都在後臺進行,對 Broker 和應用透明。

即使有 Bookie 節點出錯的情況發生時,通過新增新的可用的 Bookie 來替換失敗的 Bookie,所有 Broker 都可以繼續接受寫入,而不會犧牲主題分割槽的可用性。

獨立的可擴充套件性

由於訊息服務層和持久儲存層是分開的,因此 Apache Pulsar 可以獨立地擴充套件儲存層和服務層。這種獨立的擴充套件,更具成本效益:

當您需要支援更多的消費者或生產者時,您可以簡單地新增更多的 Broker。主題分割槽將立即在 Brokers 中做平衡遷移,一些主題分割槽的所有權立即轉移到新的 Broker。

當您需要更多儲存空間來將訊息儲存更長時間時,您只需新增更多 Bookie。通過智慧資源感知和資料放置,流量將自動切換到新的 Bookie 中。 Apache Pulsar 中不會涉及到不必要的資料搬遷,不會將舊資料從現有儲存節點重新複製到新儲存節點。

Pulsar VS. Kafka

Apache Kafka 和 Apache Pulsar 都有類似的訊息概念。 客戶端通過主題與訊息系統進行互動。 每個主題都可以分為多個分割槽。 然而,Apache Pulsar 和 Apache Kafka 之間的根本區別在於 Apache Kafka 是以分割槽為儲存中心,而 Apache Pulsar 是以 Segment 為儲存中心。

上圖顯示了以分割槽為中心和以 Segment 為中心的系統之間的差異。

在 Apache Kafka 中,分割槽只能儲存在單個節點上並複製到其他節點,其容量受最小節點容量的限制。這意味著容量擴充套件需要對分割槽重新平衡,這反過來又需要重新複製整個分割槽,以平衡新新增的代理的資料和流量。

重新傳輸資料非常昂貴且容易出錯,並且會消耗網路頻寬和 I/O。維護人員在執行此操作時必須非常小心,以避免破壞生產系統。

Kafka 中分割槽資料的重新拷貝不僅發生在以分割槽為中心的系統中的群集擴充套件上。許多其他事情也會觸發資料重新拷貝,例如副本故障,磁碟故障或計算機的故障。在資料重新複製期間,分割槽通常不可用,直到資料重新複製完成。例如,如果您將分割槽配置為儲存為 3 個副本,這時,如果丟失了一個副本,則必須重新複製完整個分割槽後,分割槽才可以再次可用。

在使用者遇到故障之前,通常會忽略這種缺陷,因為許多情況下,在短時間內僅是對記憶體中快取資料的讀取。當資料被儲存到磁碟後,使用者將越來越多地不可避免地遇到資料丟失,故障恢復的問題,特別是在需要將資料長時間儲存的場合。

相反,在 Apache Pulsar 中,同樣是以分割槽為邏輯單元,但是以 Segment 為物理儲存單元。分割槽隨著時間的推移會進行分段,並在整個叢集中均衡分佈,旨在有效地迅速地擴充套件。

Pulsar 是以 Segment 為中心的,因此在擴充套件容量時不需要資料重新平衡和拷貝,舊資料不會被重新複製,這要歸功於在 Apache BookKeeper 中使用可擴充套件的以 Segment 為中心的分散式日誌儲存系統。

通過利用分散式日誌儲存,Pulsar 可以最大化 Segment 放置選項,實現高寫入和高讀取可用性。 例如,使用 BookKeeper,副本設定等於 2,只要任何 2 個 Bookie 啟動,就可以對主題分割槽進行寫入。 對於讀取可用性,只要主題分割槽的副本集中有 1 個處於活動狀態,使用者就可以讀取它,而不會出現任何不一致。

總之,Apache Pulsar 這種獨特的基於分散式日誌儲存的以 Segment 為中心的釋出 / 訂閱訊息系統可以提供許多優勢,例如可靠的流式系統,包括無限制的日誌儲存,無需分割槽重新平衡的即時擴充套件,快速複製修復以及通過最大化資料放置實現高寫入和讀取可用性選項。

相關文章