Apache Pulsar 技術系列 - Pulsar 總覽

語言: CN / TW / HK

Apache Pulsar 是一個多租戶、高效能的服務間訊息傳輸解決方案,資料持久化依賴 Apache BookKeeper 實現,支援多租戶、低延時、讀寫分離、跨地域複製、快速擴容、靈活容錯等特性。本文將從以下幾個方面為大家介紹 Apache Pulsar的設計原理和特性。

1、Apache Pulsar 架構

2、架構設計的優勢

3、Pulsar 特性

4、總結

Apache Pulsar 架構

儲存計算分離

Apache Pulsar 是 Pub/Sub 模型的訊息系統,並且從設計上做了儲存和計算的分離,如圖一所示。

圖片

圖一 Pulsar 架構

Apache Pulsar 主要包括 Broker, Apache BookKeeper, Producer, Consumer等元件。

  • Broker:無狀態服務層,負責接收和傳遞訊息,叢集負載均衡等工作,Broker 不會持久化儲存元資料,因此可以快速的上、下線。

  • Apache BookKeeper:有狀態持久層,由一組名為 Bookie 的儲存節點組成,持久化地儲存訊息。

  • Producer :資料生產者,負責釋出資料到 Topic。

  • Consumer:資料消費者,負責從 Topic 訂閱資料。

除了上述的元件之外,Apache Pulsar 還依賴 Zookeeper 作為元資料儲存。與傳統的訊息系統相比,Apache Pulsar 在架構設計上採用了計算與儲存分離的模式,Pub/Sub 相關的計算邏輯在 Broker 上完成,資料儲存在 Apache BookKeeper 的 Bookie 節點上。

分片儲存

除了儲存、計算解耦分離的設計之外,Apache Pulsar 在儲存設計上也不同於傳統 MQ 的分割槽資料本地儲存的模式,採用的是分片儲存的模式,儲存粒度比分割槽更細化、儲存負載更均衡。Apache Pulsar 中的每個 Topic 分割槽本質上都是儲存在 Apache BookKeeper 中的分散式日誌。Topic 可以有多個分割槽,分割槽資料持久化時,分割槽是邏輯上的概念,實際儲存的單位是分片(Segment)的,如圖二,一個分割槽 Topic1-Part2 的資料由多個 Segment 組成, 每個 Segment 作為 Apache BookKeeper 中的一個 Ledger,均勻分佈並存儲在 Apache BookKeeper 群集中的多個 Bookie 節點中, 每個 Segment 具有 3 個副本。

圖片

圖二 Pulsar 分片儲存

下面可以通過圖三來看分割槽和分片儲存的區別。

圖片

圖三 分片儲存和分割槽儲存

架構設計的優勢

Apache Pulsar 計算與儲存分離的架構,以及分片儲存的設計為 Apache Pulsar 帶來了相比於傳統基於分割槽儲存 MQ 的一些優勢:

  • Broker 和 Bookie 相互獨立,方便實現獨立的擴充套件以及獨立的容錯。

  • Broker 無狀態,便於快速上、下線,更加適合於雲原生場景。

  • 分割槽儲存不受限於單個節點儲存容量。

  • 分割槽資料分佈均勻。

  • ...

可擴充套件性

由於訊息服務層和持久儲存層是分開的,因此 Apache Pulsar 可以獨立地擴充套件儲存層和服務層。

Broker 擴充套件

在 Pulsar 中 Broker 是無狀態的,可以通過增加節點的方式實現快速擴容。當需要支援更多的消費者或生產者時,可以簡單地新增更多的 Broker 節點來滿足業務需求。Pulsar 支援自動的分割槽負載均衡,在 Broker 節點的資源使用率達到閾值時,會將負載遷移到負載較低的 Broker 節點,這個過程中分割槽也將在多個 Broker 節點中做平衡遷移,一些分割槽的所有權會轉移到新的Broker節點。

Bookie擴充套件

儲存層的擴容,通過增加 Bookie 節點來實現。通過資源感知和資料放置策略,流量將自動切換到新的 Bookie 節點中,整個過程不會涉及到不必要的資料搬遷,即不需要將舊資料從現有儲存節點重新複製到新儲存節點。

圖片

圖四 Bookie 擴容

如圖四所示,起始狀態有四個儲存節點,Bookie1, Bookie2, Bookie3, Bookie4,以 Topic1-Part2為例,當這個分割槽的最新的儲存分片是 SegmentX 時,對儲存層擴容,添加了新的 Bookie 節點,BookieX,BookieY,那麼在儲存分片滾動之後,新生成的儲存分片, SegmentX+1,SegmentX+2,會優先選擇新的 Bookie 節點(BookieX,BookieY)來儲存資料。

容錯

得益於計算與儲存分離以及分片儲存的設計,Pulsar 可以實現獨立、靈活的容錯。

Broker 容錯

當 Broker 節點失敗時, 以圖五為例,當儲存分片滾動到 SegmentX 時,Broker2 節點失敗,此時生產者和消費者向其他的Broker發起請求,這個過程會觸發分割槽的所有權轉移,即將 Broker2 擁有的分割槽 Topic1-Part2 的所有權轉移到其他的 Broker(Broker3)。在 Apache Pulsar 中資料儲存和資料服務分離,所以新 Broker 接管分割槽的所有權時,它不需要複製 Partiton 的資料。新的分割槽 Owner(Broker3)會產生一個新的分片 SegmentX+1, 如果有新資料到來,會儲存在新的分片Segment x+1上,不會影響分割槽的可用性。

圖片

圖五 Broker 容錯

Bookie容錯

當 Bookie 節點失敗時,如圖六所示, 假設 Bookie 2 上的 Segment 4 損壞。Apache BookKeeper Auditor 會檢測到這個錯誤並進行復制修復。Apache BookKeeper 中的副本修復是 Segment 級別的多對多快速修復,BookKeeper 可以從 Bookie 3 和 Bookie 4 讀取 Segment 4 中的訊息,並在 Bookie 1 處修復 Segment 4。如果是 Bookie 節點故障,這個 Bookie 節點上所有的 Segment 會按照上述方式複製到其他的Bookie節點。所有的副本修復都在後臺進行,對Broker和應用透明,Broker 會產生新的Segment 來處理寫入請求,不會影響分割槽的可用性。

圖片

圖六 Bookie 容錯

無限制的分割槽儲存

分片儲存解決了分割槽容量受單節點儲存空間限制的問題,當容量不夠時,可以通過擴容 Bookie 節點的方式支撐更多的分割槽資料,也解決了分割槽資料傾斜問題,資料可以均勻的分配在 Bookie 節點上。Broker 和 Bookie 靈活的容錯以及無縫的擴容能力讓 Apache Pulsar 具備非常高的可用性。

Pulsar 特性

基於上述的設計特點,Pulsar 提供了很多特性,以下做簡要的介紹。

讀寫分離

Pulsar另外一個有吸引力的特性是提供了讀寫分離的能力,讀寫分離保證了在有大量滯後消費(磁碟IO會增加)時,不會影響服務的正常執行,尤其是不會影響到資料的寫入。讀寫分離的能力由 Apache BookKeeper 提供,簡單說一下 Bookie 儲存涉及到的概念:

  • Journals:Journal 檔案包含了 BookKeeper事務日誌,在 Ledger 更新之前,Journal 保證描述更新的事務寫入到 Non-volatile 的儲存介質上。

  • Entry logs:Entry 日誌檔案管理寫入的 Entry,來自不同 ledger 的 entry 會被聚合然後順序寫入。

  • Index files:每個 Ledger都有一個對應的索引檔案,記錄資料在 Entry 日誌檔案中的 Offset 資訊。

Entry 的讀寫入過程如圖七所示,資料的寫入流程:

  • 資料首先會寫入 Journal,寫入 Journal 的資料會實時落到磁碟。

  • 然後,資料寫入到 Memtable ,Memtable 是讀寫快取。

  • 寫入 Memtable 之後,對寫入請求進行響應。

  • Memtable 寫滿之後,會 Flush 到 Entry Logger 和 Index cache,Entry Logger 中儲存了資料,Index cache 儲存了資料的索引資訊,然後由後臺執行緒將 Entry Logger 和 Index cache 資料落到磁碟。

資料的讀取流程:

  • 如果是 Tailing read 請求,直接從 Memtable 中讀取 Entry。

  • 如果是 Catch-up read(滯後消費)請求,先讀取 Index資訊,然後索引從 Entry Logger 檔案讀取 Entry。

圖片

圖七 Bookie的資料寫入和讀取

一般在進行 Bookie 的配置時,會將 Journal 和Ledger 儲存磁碟進行隔離,減少 Ledger 對於 Journal寫入的影響,並且推薦 Journal 使用效能較好的 SSD 磁碟,讀寫分離主要體現在:

  • 寫入 Entry 時,Journal 中的資料需要實時寫到磁碟,Ledger的資料不需要實時落盤,通過後臺執行緒批量落盤,因此寫入的效能主要受到 Journal 磁碟的影響。

  • 讀取 Entry 時,首先從 Memtable 讀取,命中則返回;如果不命中,再從 Ledger 磁碟中讀取,所以對於 Catch-up read 的場景,讀取資料會影響 Ledger 磁碟的 IO,對 Journal 磁碟沒有影響,也就不會影響到資料的寫入。

所以,資料寫入是主要是受 Journal 磁碟的負載影響,不會受Ledger 磁碟的影響。另外,Segment 儲存的多個副本都可以提供讀取服務,相比於主從副本的設計,Apache Pulsar 可以提供更好的資料讀取能力。通過以上分析,Apache Pulsar 使用 Apache BookKeeper 作為資料儲存,可以帶來下列的收益:

  • 支援將多個 Ledger 的資料寫入到同一個 Entry logger 檔案,可以避免分割槽膨脹帶來的效能下降問題。

  • 支援讀寫分離,可以在滯後消費場景導致磁碟IO上升時,保證資料寫入的不受影響。

  • 支援全副本讀取,可以充分利用儲存副本的資料讀取能力。

多種消費模型

Apache Pulsar 提供了多種訂閱方式來消費訊息,分為三種類型:獨佔(Exclusive),故障切換(Failover)或共享(Share)。

圖片

圖八 消費模型

  • Exclusive 獨佔訂閱 :在任何時間,一個消費者組(訂閱)中有且只有一個消費者來消費 Topic 中的訊息。

  • Failover 故障切換 :多個消費者(Consumer)可以附加到同一訂閱。但是,一個訂閱中的所有消費者,只會有一個消費者被選為該訂閱的主消費者。其他消費者將被指定為故障轉移消費者。當主消費者斷開連線時,分割槽將被重新分配給其中一個故障轉移消費者,而新分配的消費者將成為新的主消費者。發生這種情況時,所有未確認(ack)的訊息都將傳遞給新的主消費者。

  • Share 共享訂閱 :使用共享訂閱,在同一個訂閱背後,使用者按照應用的需求掛載任意多的消費者。訂閱中的所有訊息以迴圈分發形式傳送給訂閱背後的多個消費者,並且一個訊息僅傳遞給一個消費者。當消費者斷開連線時,所有傳遞給它但是未被確認(ack)的訊息將被重新分配和組織,以便傳送給該訂閱上剩餘的剩餘消費者。

多種ACK模型

訊息確認(ACK)的目的就是保證當發生故障後,消費者能夠從上一次停止的地方恢復消費,保證既不會丟失訊息,也不會重複處理已經確認(ACK)的訊息。在 Pulsar 中,每個訂閱中都使用一個專門的資料結構--遊標(Cursor)來跟蹤訂閱中的每條訊息的確認(ACK)狀態。每當消費者在分割槽上確認訊息時,遊標都會更新。Pulsar 提供兩種訊息確認方法:

  • 單條確認(Individual Ack),單獨確認一條訊息。被確認後的訊息將不會被重新傳遞。

  • 和累積確認(Cumulative Ack),通過累積確認,消費者只需要確認它收到的最後一條訊息。

圖九說明了單條確認和累積確認的差異(灰色框中的訊息被確認並且不會被重新傳遞)。對於累計確認,M12 之前的訊息被標記為 Acked。對於單獨進行 ACK,僅確認訊息 M7 和 M12, 在消費者失敗的情況下,除了 M7 和 M12 之外,其他所有訊息將被重新傳送。

圖片

圖九 ACK模型

跨地域複製

Apache Pulsar 的跨地域複製機制(Geo-Replication)提供了一種全連線的非同步複製,可以滿足多個數據中心資料同步的使用場景。

圖片

圖十 Geo-replication

如圖十所示,有三個 Apache Pulsar 叢集,分佈於北京、上海和廣州,使用者建立的一個 Topic T1 設定了跨越三個資料中心做互備。在三個資料中心中,分別有三個生產者:P1、P2、P3,它們往主題 T1 中釋出訊息;有兩個消費者:C1、C2,訂閱了這個主題,接收主題中的訊息。當訊息由本資料中心的生產者釋出成功後,會立即複製到其他兩個資料中心。訊息複製完成後,消費者不僅可以收到本資料中心產生的訊息,也可以收到從其他資料中心複製過來的訊息。

總結

Pulsar 採用了計算、儲存分離的設計,並且儲存在邏輯上分割槽,物理上分片,具有一些傳統類 kafka 的 MQ 所不具備的優勢,也解決了一些業界的痛點,Pulsar 目前社群比較活躍,還處於快速發展的階段,除了以上的特性之外,Pulsar還可以支援事務、SQL查詢、Function等功能,另外 Pulsar 支援 protocol handler,比如 KoP(Kafka on Pulsar), 可以原生支援 Kafka 協議的資料,對於這些特性,我們會在後續的文章中做介紹。