翟佳:高可用、強一致、低延遲——BookKeeper的存儲實現

分享嘉賓:翟佳 StreamNative 聯合創始人

編輯整理:張曉偉 美團點評

出品平臺:DataFunTalk


導讀:多數讀者們瞭解BookKeeper是通過Pulsar,實際上BookKeeper在數據庫和存儲場景都有着非常廣泛的應用。BookKeeper是Pulsar的底層存儲,Pulsar有着廣泛數據入口,Pulsar跟Kafka及各類MQ(RabbitMQ、ACTIVEMQ)的較大區別是Pulsar是統一的雲原生消息流平臺,不但是分佈式系統,而且做了存算分離,可以讓用戶在雲的環境下,體驗到雲原生的優勢,例如隨意擴縮容、數據靈活遷移複製等。希望通過本文,讓大家對Pulsar底層的BookKeeper有更深入的瞭解。

今天的介紹會圍繞下面四點展開:

  • BookKeeper的簡介
  • BookKeeper的特性
  • BookKeeper存儲介質的演進
  • BookKeeper的社區資源

--

01 BookKeeper的簡介

1. 業務場景需求的統一

Pulsar裏有很重要的概念是“統一”,這個統一的特性是由BookKeeper支持實現的。這裏的統一是指需求的統一,在消息場景下,用戶場景分兩類:

第一類是線上業務場景,例如1984年誕生的IBM MQ到現在的各類開源MQ解決的是線上業務場景,這些MQ的服務質量會對業務服務質量有着直接的影響,所以這類需求對數據質量,例如對數據持久性、數據延遲、消費模型的靈活性有較強的要求。

第二類是大數據場景,例如2010年左右隨着實時計算的廣泛使用,Kafka的這種高帶寬和高吞吐使用需求。

file

由於面向場景不同、技術棧不同,這兩種場景在業務上又同時存在,給業務帶來不同的基礎設施API、不同的使用方式、不同系統的運維成本等問題。所以Pulsar針對這些問題,做了兩層API的統一:既兼容MQ的併發消費模型,提供比較好的服務質量,同時通過底層存儲層抽象,可以提供很高的吞吐和帶寬,這就是我們要介紹的Apache BookKeeper項目。

file

2. Apache BookKeeper簡介

很多服務裏都有日誌,例如MySQL的binlog和HDFS的namenode的editlog,都是對日誌的一個抽象,而BookKeeper就是把這個抽象變成了一個分佈式的服務,擺脫了對單機容量瓶頸的限制,把日誌變成了可無限擴展的服務。BookKeeper使用packet source協議和ZooKeeper的zap協議,通過log append only的方式實現了低延遲和高吞吐。在APCP裏選擇CP,而availability是通過多副本併發的方式提供高可用,BookKeeper有着低延遲、高吞吐、持久化、數據的強一致性、服務的高可用、單節點可以存儲很多日誌、IO隔離等優勢,針對這些特性在後文會展開介紹。

3. BookKeeper的誕生

BookKeeper也是Apache的一個項目,同樣是由雅虎捐獻誕生,原本是爲了應對雅虎開源HDFS裏元數據存儲的需求。

下圖是字節跳動技術文章的一個圖,主要是呈現在字節跳動如何用BookKeeper支撐元數據服務,支撐起EB級別的HDFS集羣。這個集羣DN有好幾萬臺,需要很多NameNode,就需要一個可以保障active/standby/observer NameNode之間強一致性的日誌服務,單機容量瓶頸下很難支撐這麼大的體量時,引入了一個分佈式的日誌服務,這就是BookKeeper誕生的場景。隨着HDFS大規模的問題開始出現之後,BookKeeper成爲了HDFS在HA上的剛需需求,例如在EMC內部的HDFS集羣,也是用的BookKeeper來做NameNode的editlog服務。BookKeeper是一種分佈式場景下很常見的複製狀態機的實現(通過複製log,保持各個節點狀態機的同步,A節點持久化log後,把log同步到B節點,在B節點進行log的一個重放,讓B節點達到跟A節點一樣的一個狀態)。由於在HDFS場景中,保存的只是NN的變更日誌,所以算是元數據的元數據,對數據一致性、對吞吐、對時延的要求自然極高。

file

4. BookKeeper使用案例

BookKeeper也有侷限性,是append only的一個抽象變成了分佈式服務,相對而言比較底層。所以用戶多是一些比較大的互聯網公司或其他有大數據量的需求的用戶,這些用戶會在BookKeeper之上做一些二次開發,例如Pulsar在BookKeeper之上做了一層broker服務,對BookKeeper的每個分片做一些管理然後將其作爲數據的存儲服務。

類似的還有Twitter和Salesforce。Twitter的技術棧是構建在實時計算上的,在Twitter內部,BookKeeper是作爲很重要的基礎設施,不但有類似Pulsar的服務eventbus,還有其他使用場景例如搜索、廣告、Stream computing, 以及作爲類似KV存儲的Manhattan Database的元數據服務,這些場景都用到了BookKeeper。在規模上,Twitter BookKeeper有兩個集羣,每個集羣約有1500個節點,每天有17PB的數據,每秒1.5萬億的records。而在Salesforce的使用背景,是Salesforce想去掉對Oracle的依賴,所以自研了類似Amazon Aurora的NewSQL Database,其內部很多跟元數據相關或有一致性要求的服務都是通過BookKeeper來滿足的,並且也有部分後端場景將BookKeeper作爲存儲服務去用。

--

02 BookKeeper的特性

1. BookKeeper基本概念

  • Ledger

可以理解爲BookKeeper是會計,Ledger是賬本,每個賬本是記錄信息的一個單元,寫完之後轉爲closed狀態(只讀),最新的賬本是打開狀態(openLedger),以append only的方式持續存儲數據。

  • Fragment

可以理解爲BookKeeper內部維護的一個以append only的方式添加的數據組。

Fragment之下就是用戶以append only的方式追加的一條條數據。

file

2. BookKeeper的節點對等架構

openLedger時有3個參數:Ensemble選擇幾個節點存儲這個賬本,Write Quorum控制數據寫幾個副本(併發寫,不同於Kafka或HDFS,BookKeeper沒有數據節點之間主從同步的關係,把數據同步的協調者從服務端移到了客戶端),Ack Quorum控制等幾個副本返回ack。

以下圖爲例openLedger(5,3,2),在保存這個賬本時,選擇了5個節點,但是隻寫3個副本,等2個副本來返回ack。第一個參數一般可用於調整併發度,因爲寫3個副本是通過輪轉的方式寫入,例如第1個record是寫1-3節點,第2個record寫2-4節點,第3個record寫3-5節點,第4個record寫4-5和1節點這樣輪轉。這種方式即便3個副本,也可以把5個節點都用起來。

file

這幾個參數便捷的特性可讓用戶通過機架感知、機房感知、resource感知等各種方式進行靈活設置。當選好節點後節點之間的排序就已完成,每個record會帶個index,index和節點已有綁定關係,例如index爲1的,都放在123上,爲2的都放在234上。通過這種方式可以讓我們知道每個節點存了哪些消息,當某個節點宕機,根據這個節點的位置信息,把對應record還在哪些節點上有副本的信息找出來進行多對多的恢復。這麼做的另一個好處是不用再維護元數據信息,只需要有每個節點記錄index信息,在openLedger時記錄好每個節點的順序即可。

openLedger(5,3,2)數據存儲結構就是下圖中右邊的結構,如果選擇Ensemble=3,Write Quorum=3,數據存儲結構就是下圖左邊的結構:

file

綜上,用戶可以通過Ensemble來調整讀寫帶寬,通過Write Quorum調整強一致性的控制,通過Ack Quorum權衡在有較多副本時也可以有較低的長尾時延(但一致性就可能有一定的損失)。

3. BookKeeper可用性

  • 讀的高可用

讀的訪問是對等的,任意一個節點返回就算讀成功。這個特性可以把延遲固定在一個閾值內,當遇到網絡抖動或壞節點,通過延遲的參數避障。例如讀的延遲時間2ms,讀節點3超過2ms,就會併發地讀節點4,任意一個節點返回就算讀成功,如下圖Reader部分。

  • 寫的高可用

在openLedger時會記錄每個節點的順序,假如寫到5節點宕機,會做一次元數據的變更,從這個時間開始,先進行數據恢復,同時新的index中會把5節點變爲6節點,如下圖x節點替換5節點:

file

4. BookKeeper一致性

BookKeeper底層節點對等設計讓寫入數據的Writer成爲了協調者,Writer來保存數據是否存儲成功的狀態,例如節點是否出現問題、副本夠不夠、切換Fragment時要不要做數據恢復、在寫入過程中出現宕機時,通過fencing的方式防止腦裂等。所以,Writer維護了2個index:LastAddPushed和LastAddConfirmed。

LastAddPushed會隨消息ID遞增,LastAddConfirmed則記錄最後一個連續的消息成功寫入了(例如Ack Quorum爲2,有2個成功返回了即爲成功),但因爲返回順序不一定與消息順序一致,例如123個消息,3的消息先返回了,2的還未返回,按連續的規則就是2不是3。

file

5. BookKeeper與Raft的對比

在底層原理上,Raft與BookKeeper有很多類似的地方,Raft每個數據寫入的組織形式是term,跟BookKeeper的segment類似,每個term也會選擇一組節點存儲數據,然後不斷往後追加數據,通過數據節點之間的協同保證數據一致性。

在數據結構上,Raft在保存數據時有Entry,Entry除了帶本身的index還會帶上last committed index,與BookKeeper中的LastAddConfirmed較爲類似,只是BK是通過Writer來協調數據在不同節點的一致性,Raft有leader來協調數據在不同節點的一致性。

file
file

6. BookKeeper的IO讀寫分離

下圖是每個數據節點的數據流轉過程,數據寫入時,Writer通過append only方式寫入到Journal,Journal在把數據寫到內存的同時會按一定頻率(默認1ms或500 byte)把數據持久化到Journal Device裏,寫完後會告訴Writer這個節點寫入成功了(持久化到磁盤是默認配置)。

Journal在數據寫入時有寫到內存中,接下來在內存中做排序(用於解決如果按寫的順序讀會導致分區隨機性強的問題),然後把數據刷到數據盤中。讀的時候,如果讀最新的數據,可以直接從內存裏返回,如果讀歷史數據,也只去讀數據盤,不會對Journal Device寫入有影響。這樣針對有讀瓶頸或寫瓶頸的用戶,可以把Journal Disk或Ledger Disk換成SSD盤,提升性能,並且防止讀寫的互相干擾。

file

--

03 BookKeeper的存儲介質演變

1. BookKeeper的Disk演進

在演進過程中,因爲順序讀的情況比較多,所以讀的部分變化不大,但在寫的這部分經歷了HDD到SSD再到NVMe SSD,再到現在部分用戶換成了Intel的PMem的過程(如下圖所示)。在換到NVMe SSD時,部分用戶通過多目錄的方式可以把SSD的IO帶寬打的很滿。

file

2. PMEM在BookKeeper上的應用

PMem的特性非常匹配Journal Disk,單塊PMem可以達到3-4GB的帶寬,不但能提供高帶寬吞吐而且可持久化。PMem容量相比SSD比較小、相比內存又比較大,在剛推出時單條128GB,有着GB級別的吞吐和ns級別的延遲。

高吞吐低容量的PMem非常適合Journal持久話刷盤的需求,例如宕機後,需要對沒刷到磁盤的這部分數據做恢復,需要Journal做replay log重放,由於只是增量日誌而非全量數據,所以並不需要很大的容量,正好和PMem容量不大相匹配。而且,PMem的壽命會比SSD的壽命長一些,例如在每天同樣寫入量下SSD可能只能用1年而PMem預計可以使用4-5年。

雅虎(現在是Verizon Media)有實際通過PMEem優化BookKeeper的案例,在只增加5%的單機成本情況下提升了5倍的帶寬吞吐和低於5ms的時延保障(BookKeeper社區與Intel正在合作做性能測試,預計未來會產出白皮書說明)。

在雅虎案例中用10臺Pulsar(底層是用PMem做Journal Disk的BookKeeper)替換了33臺Kafka,比原Kafka方案成本降低了一半,產出的對比結果如下:

file

--

04 社區資源

  • 團隊構成

由Apache Pulsar核心研發團隊創立,同時有Apache Pulsar和Apache BookKeeper項目管理委員會(PMC)主席,有6名Apache Pulsar PMC成員和3名Apache BookKeeper PMC成員,有約20名 Apache Committer。

  • 里程碑

公司成立於2019年,2020年發佈商業化產品StreamNative Cloud,目前有50+付費客戶,覆蓋金融、IoT、互聯網、製造多個行業。

  • 優勢

是社區和代碼的構建維護者,有全球最專業的Pulsar設計開發、運維、管理團隊的7*24小時服務,提供開箱即用的雲服務和諮詢培訓服務。

file
file


今天的分享就到這裏,謝謝大家。


分享嘉賓:

file
本文首發於微信公衆號“DataFunTalk”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章