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 協議的數據,對於這些特性,我們會在後續的文章中做介紹。