Pulsar中的邏輯存儲體系使用的是Apache BookKeeper。本文僅在Pulsar的背景下介紹BookKeeper。
BookKeeper將數據存儲至集群中的節點上,每個BookKeeper節點稱為Bookie。Pulsar和BookKeeper都使用Apache Zookeeper來存儲元數據和監控節點健康狀況。
Bookkeeper自身就可以組成一個集群,這個集群是 Client-Server 模型,集群的 metadata 可以利用一個 Ledger 語義存儲(參考),在 Client 層面保證 各個 Bookie 之間的數據一致性。Pulsar 則是一種 Client-Proxy-Server 模型,基于 Broker 這個 Proxy 來保證一個 Topic Parition 內的數據一致性。
Pulsar 的底層數據 以 Ledger(上圖中的 Segment 就是 Ledger) 形式存儲在多個 BookKeeper 上,當集群擴容添加 Bookies 后,Pulsar 會在新的 Bookie 上創建新的 Segment(即 Bookeeper 的 Ledger),所以不需要再擴容時候像 Kafka 一樣進行 Rebalance 操作,其結果就是 Fragments跨多個Bookies以帶狀分布。但是這樣的結果就是同一個 Ledger 的 Fragments 分布在多個 Bookie 上,導致讀取和寫入會在多個 Bookies 之間跳躍。Topic的 Ledger 和 Fragment 之間映射關系等元數據存儲在 Zookeeper 中,Pulsar Broker 需要實時跟蹤這些關系進行讀寫流程。
Pulsar 有一個 Ledger的所有權(ownership) 的概念,其意義為某個 Ledger 數據所在的 Bookie。除去創建新 Ledger 的情況,當集群擴容 Pulsar 把數據寫入新的 Bookie 或者 當前Fragment使用Bookies發生寫入錯誤或超時 時,Ledger的所有權 都會發生改變。
上圖描述了 Bookie 集群擴容的情況。圖中 Bookie X 和 Bookie Y 被添加到集群中,Broker 根據 IDC、機架、各個 Bookie 的容量等信息根據各種策略把 Segment X+1 和 X+2 存儲到兩個 Bookie 節點中,最終確保群集中各個 Bookie 之間的流量均衡。
上圖描述了 Bookie 2 發生故障時,其 Segment 4 的修復過程。Broker 2 選取 Bookie 1 作為 Segment 4 的副本集,然后由 Bookie 自己的 Auditor 線程完成數據復制工作,整個過程對 Broker 和應用透明,功能的可用性不受影響。
每個Ledger有三個關鍵配置:
Ensemble Size (E)
Write Quorum Size (Qw)
Ack Quorum Size (Qa)
這些配置應用到Topic級別,然后pulsar會在Topic使用的BookKeeper Ledgers/Fragments上設置。
注意:Ensemble表示將要寫入的實際的Bookies數量,以下用E表示。E表示Pulsar需要使用的Bookies數量。在配置時您至少需要E個bookies才能正常的使用。默認情況下,從可用的bookies列表中隨機選取E個bookies(每個bookie在Zookeeper中注冊自己)。
Ensemble Size (E) 決定了Pulsar寫入Ledger可用的Bookies池的大小。每個Fragment可以有不同的Bookies列表,Broker將在創建Fragment時選擇一組Bookies,E的數量是一致的。必有足夠的Bookies數量(> E)。
Write Quorum (Qw) 是Pulsar將要寫入的實際的Bookies數量。可以等于或者小于E。
當Qw小于E時,以條帶化的方式分配讀/寫即每個Bookie只提供讀寫請求的子集。
如上圖,Bookie Ensemble 數目是 5,Qw 為 3,Broker 可以用這種條帶化方式把數據 Entry x 寫入各個 Bookie。每個 Bookie 有一個 Auditor 線程跟蹤自身負責的 Entry 集合是否有數據副本缺失【如當 Bookie 1 接收到 Entry 6 時,Auditor 會檢測 Entry 5 是否已經收到】,當其發現數據有缺失的時候會從副本集中其他副本復制數據。
Ack Quorum (Qa) 是確認寫入Bookies的數量,Pulsar Broker將確認發送給客戶端。為了一致性,Qa應該是:(Qw + 1) / 2 或者更大。
(Qa == Qw) 或(Qa == Qw - 1) ---> 這樣避免單節點響應緩慢而改善寫入延遲。
當創建一個新的Topic或者Ledger滾動時會創建一個新的Ledger。Ledger在以下這些情況會發生滾動并創建新的Ledger:
- 已達到Ledger的大小或時間限制。
- Ledger的所有權(Pulsar Broker的所有權)發生變化(稍后會詳細介紹)。
以下情況會創建新的Fragment:
- 創建新的Ledger。
- 當前Fragment使用Bookies發生寫入錯誤或超時。
對比
1 kafka
kafka模型的優點在于簡單快捷。所有讀寫都是順序的。不好的是,單個節點必須有足夠的磁盤空間來處理副本,因此非常大的副本可能會迫使你是用非常大的磁盤。第二個缺點是,在集群擴展時必須做Rebalance。這個過程是比較痛苦的,需要良好的計劃和執行來保證沒有任何故障的情況下分散節點的存儲壓力。
2 pulsar
Pulsar + BookKeeper模型。Topic中的數據分布在多個Bookies上。Topic被分割成Ledgers,Ledgers被分割成Fragments分布在Fragment使用的Bookies上。當需要做集群擴展時,只需添加更多Bookies,它們就會在創建新的Fragment時開始在的Bookies上寫入數據,不再需要kafka的Rebalance操作。但是,讀取和寫入是在Bookies之間跳躍。