Apache BookKeeper:一種面向Apache Pulsar的合格的存儲系統
譯文?譯者 | 布加迪
審校 | 孫淑娟
如果您熟悉Kafka和RocketMQ等消息系統,可能知道服務通常與其架構中的存儲密切相關。與它們不同的是,Apache Pulsar在設計時采用了將存儲與計算分開的兩層架構,這實際上在其無狀態代理上進行。Pulsar依賴Apache BookKeeper服務器(又叫bookies)進行持久存儲。本文側重介紹BookKeeper基礎知識,表明它如何為所處理的數據實現高可用性。
圖1
Apache BookKeeper簡介
BookKeeper最初在雅虎開發,代表了一種可靠的高性能存儲系統。它提供分布式可擴展的存儲服務,具有低延遲和強容錯性的優點。這些充分說明了為什么它能夠充當Pulsar的存儲層。BookKeeper將數據存儲在分類帳(ledger)中,分類帳只能追加且不可變。借助特殊的復制協議,BookKeeper以并發方式在多個節點上安全地存儲日志條目,因而具有高可用性。
顧名思義,BookKeeper和分類帳在云原生環境中大有用途。不妨設想一下簿記員使用分類帳記錄所有相關賬戶信息,以跟蹤企業的財務狀況。
Apache BookKeeper中的關鍵概念
為了更好地了解BookKeeper如何存儲數據,不妨先看一下幾個基本概念。
- Bookie
Bookie是BookKeeper中的存儲服務器或節點,彼此同等。BookKeeper強大的動態擴展功能(尤其是在容器化環境中)歸功于無主節點(leaderless)設計。
- Ensemble
用于存儲分類帳條目的可用bookie的集合,即寫入條目的節點。當一個bookie失效時,處理寫入它的客戶端將換成一個新的bookie,這名為“ensemble change”。在Pulsar的計算存儲分離架構中,客戶端應用程序不需要關心存儲層中實際發生的事情。
- 分類帳
分類帳是BookKeeper中的基本存儲單元,在Pulsar中又叫Segment。BookKeeper客戶端負責創建和刪除分類帳,并從分類帳中讀取條目。滿足某些條件時(比如條目數或壽命達到預設閾值),分類帳將被關閉,之后再無法向其寫入數據,只允許讀取。任何客戶端都可以創建分類帳。理想情況下,創建分類帳的所有者客戶端應該是關閉它的客戶端。一旦關閉,分類帳不可變。分類帳是最小的刪除單位,這意味著您只能刪除整個分類帳,而不能刪除分類帳中的單個條目。
除了用于存儲普通消息的分類帳外,BookKeeper還有一種特殊的分類帳,即游標分類帳。游標為Pulsar中的消息消費和確認提供跟蹤機制。每個訂閱都有一個與之關聯的游標,游標存儲消息消費和確認的位置信息。消費者可能根據訂閱類型來共享同樣的游標。我們在這里不詳細介紹這個話題。我們只需知道Pulsar在BookKeeper中為每個訂閱維護一個分類帳。在消費者處理消息(向代理發送確認)、代理收到確認之后,代理隨后相應地更新游標分類帳。更具體地說,Pulsar定期匯總綁定到同一訂閱的所有消費者的所有確認信息作為條目,并將其寫入bookie。這個過程與編寫普通消息基本相同。
- 片段
片段在bookie的分類帳中存儲連續序列的條目。分類帳可能含有一個或多個片段。作為BookKeeper中最小的分布單元,單個分類帳的片段可以分散在不同的bookie中。這意味著嚴格來講,存儲在單個bookie的數據是分類帳的片段。對于單個片段而言,如果寫入 bookie失敗,會選擇新的bookie進行寫入(即上面提到的“ensemble change”)。結果,將在bookie上創建新片段。請注意,這兩個片段屬于同一個分類帳,但屬于不同的ensemble。
- 條目
條目含有寫入分類帳的實際數據。每個分類帳可能含有不同數量的條目。每個條目都有條目ID作為其在分類帳中的唯一標識符。
- 消息
消息是存儲在條目中的特定信息。消息可以分為兩種:單條消息和批量消息。
批量消息本質上是一系列單條消息。在客戶端啟用消息批處理后,消息將在從生產者發送到代理之前作為一個整體進行分組。Brokers然后調用BookKeeper客戶端,將批量消息寫入bookie。當消費者從代理讀取消息時,代理將批量消息分發給它們。請注意,批量消息在客戶端合并和拆分。您可以使用batchingMaxPublishDelay(批量處理待發送消息的時間段)和batchingMaxMessages(批量消息中的最大消息數)等參數,為生產者定制批量消息配置。
注意:每個條目可能包含一條或多條消息。如果禁用消息批量處理,一個條目僅存儲一條消息。
圖2
視用例而定,您可以選擇啟用或禁用消息批量處理。與大多數分布式消息系統不同,Pulsar支持消息隊列和流傳輸。在消息隊列場景中,高吞吐量通常不是必須的,因此很少在客戶端啟用消息批量處理。相比之下,在流傳輸情形下,消息的生成速度要快得多,這需要批量處理,以便生產者可以將消息作為更大的包來發送。
數據高可用性
為了保證數據的高可用性,BookKeeper采用了一種仲裁機制向bookie并行寫入數據。具體來說,我們可以為要創建的新分類帳定義以下三個關鍵整數:
- Ensemble Size(E):寫入存儲在分類帳中的消息的可用bookie的數量。
- Write Quorum(WQ):要寫入的消息的副本,或同時保存條目(或其所屬片段)的bookie的數量。WQ可以等于或小于E,但不能小于1或AQ。
- Ack Quorum(AQ):在寫入成功之前,代理需要接收的確認數量。如果達到這個值,代理將向客戶端發回確認信息。否則,寫入失敗。
這三個參數可以分別在代理、命名空間和主題級別進行配置。比如在代理級別,編輯Pulsar包的conf目錄中的broker.conf文件,并設置所需的值:
屬性文件 # Number of bookies to use when creating a ledger managedLedgerDefaultEnsembleSize=2 # Number of copies to store for each message managedLedgerDefaultWriteQuorum=2 # Number of guaranteed copies (acks to wait before a write is complete) managedLedgerDefaultAckQuorum=2 |
注意:我們可以根據對一致性的需求來配置以上參數。比如說,WQ=AQ表示最高級別的一致性。在這種情況下,消息只有在收到所有副本的確認后才能成功持久化。當AQ比較?。ū热鏏Q = 1)時,延遲會較低,但是數據丟失風險較大。一般來說,最好設置AQ ≥ (WQ + 1)/2。
比如在下圖中,我們設置E = 5、WQ = 3和AQ = 2。這意味著:
- 5個bookie可用于將數據存儲在分類帳中。
- 一個條目的3個副本存儲在3個不同的bookie上。
- 收到來自2個bookie的確認時,表示條目寫入成功。
圖3
數據使用循環分布寫入bookie。這么設計是由于,它可以充分利用池中所有bookie的處理能力。如下所示,Entry 1寫入Bookie 1、Bookie 2和Bookie 3,Entry 2寫入Bookie 2、Bookie 3和Bookie 4,以此類推。
圖4
循環方法提供了一種簡單的方法來快速找出通過條目ID來存儲特定條目副本的bookie。比如說,我們知道條目2在Bookie 2、Bookie 3和Bookie 4上復制。2 mod 5等于 2,這意味著對于特定的條目X而言,如果X mod 5等于2,條目X就存儲在Bookie 2上、Bookie 3和Bookie 4上,比如條目 7 (X=7)。
使用Apache BookKeeper
當您安裝Pulsar集群時,BookKeeper將一同部署。如果您想運行BookKeeper,不需要單獨下載其代碼。相反,下載Pulsar并在bin目錄中運行./pulsar-daemon start bookie命令。如果您使用Pulsar社區提供的Helm chart將其安裝在Kubernetes集群上,bookie Pods則部署在StatefulSet 中。
結語
本文介紹了BookKeeper的基礎知識,分析了如何將數據寫入bookie以實現高可用性。我們可以將BookKeeper簡單地視為一個數據庫,因為它不包含任何業務邏輯。該開源工具具有出色的可擴展性、強大的容錯性和低延遲,具備成為合格的云原生存儲系統所需的特性,為Pulsar的獨特架構提供了堅實的支持。
原文標題:??Apache BookKeeper: What Makes A Qualified Storage System for Apache Pulsar??,作者:Sherlock Xu