翟佳:高可用、强一致、低延迟——BookKeeper的存储实现
分享嘉賓:翟佳 StreamNative 聯(lián)合創(chuàng)始人
編輯整理:張曉偉 美團(tuán)點(diǎn)評(píng)
出品平臺(tái):DataFunTalk
導(dǎo)讀:多數(shù)讀者們了解BookKeeper是通過(guò)Pulsar,實(shí)際上BookKeeper在數(shù)據(jù)庫(kù)和存儲(chǔ)場(chǎng)景都有著非常廣泛的應(yīng)用。BookKeeper是Pulsar的底層存儲(chǔ),Pulsar有著廣泛數(shù)據(jù)入口,Pulsar跟Kafka及各類(lèi)MQ(RabbitMQ、ACTIVEMQ)的較大區(qū)別是Pulsar是統(tǒng)一的云原生消息流平臺(tái),不但是分布式系統(tǒng),而且做了存算分離,可以讓用戶在云的環(huán)境下,體驗(yàn)到云原生的優(yōu)勢(shì),例如隨意擴(kuò)縮容、數(shù)據(jù)靈活遷移復(fù)制等。希望通過(guò)本文,讓大家對(duì)Pulsar底層的BookKeeper有更深入的了解。
今天的介紹會(huì)圍繞下面四點(diǎn)展開(kāi):
- BookKeeper的簡(jiǎn)介
- BookKeeper的特性
- BookKeeper存儲(chǔ)介質(zhì)的演進(jìn)
- BookKeeper的社區(qū)資源
--
01 BookKeeper的簡(jiǎn)介
1. 業(yè)務(wù)場(chǎng)景需求的統(tǒng)一
Pulsar里有很重要的概念是“統(tǒng)一”,這個(gè)統(tǒng)一的特性是由BookKeeper支持實(shí)現(xiàn)的。這里的統(tǒng)一是指需求的統(tǒng)一,在消息場(chǎng)景下,用戶場(chǎng)景分兩類(lèi):
第一類(lèi)是線上業(yè)務(wù)場(chǎng)景,例如1984年誕生的IBM MQ到現(xiàn)在的各類(lèi)開(kāi)源MQ解決的是線上業(yè)務(wù)場(chǎng)景,這些MQ的服務(wù)質(zhì)量會(huì)對(duì)業(yè)務(wù)服務(wù)質(zhì)量有著直接的影響,所以這類(lèi)需求對(duì)數(shù)據(jù)質(zhì)量,例如對(duì)數(shù)據(jù)持久性、數(shù)據(jù)延遲、消費(fèi)模型的靈活性有較強(qiáng)的要求。
第二類(lèi)是大數(shù)據(jù)場(chǎng)景,例如2010年左右隨著實(shí)時(shí)計(jì)算的廣泛使用,Kafka的這種高帶寬和高吞吐使用需求。
由于面向場(chǎng)景不同、技術(shù)棧不同,這兩種場(chǎng)景在業(yè)務(wù)上又同時(shí)存在,給業(yè)務(wù)帶來(lái)不同的基礎(chǔ)設(shè)施API、不同的使用方式、不同系統(tǒng)的運(yùn)維成本等問(wèn)題。所以Pulsar針對(duì)這些問(wèn)題,做了兩層API的統(tǒng)一:既兼容MQ的并發(fā)消費(fèi)模型,提供比較好的服務(wù)質(zhì)量,同時(shí)通過(guò)底層存儲(chǔ)層抽象,可以提供很高的吞吐和帶寬,這就是我們要介紹的Apache BookKeeper項(xiàng)目。
2. Apache BookKeeper簡(jiǎn)介
很多服務(wù)里都有日志,例如MySQL的binlog和HDFS的namenode的editlog,都是對(duì)日志的一個(gè)抽象,而B(niǎo)ookKeeper就是把這個(gè)抽象變成了一個(gè)分布式的服務(wù),擺脫了對(duì)單機(jī)容量瓶頸的限制,把日志變成了可無(wú)限擴(kuò)展的服務(wù)。BookKeeper使用packet source協(xié)議和ZooKeeper的zap協(xié)議,通過(guò)log append only的方式實(shí)現(xiàn)了低延遲和高吞吐。在APCP里選擇CP,而availability是通過(guò)多副本并發(fā)的方式提供高可用,BookKeeper有著低延遲、高吞吐、持久化、數(shù)據(jù)的強(qiáng)一致性、服務(wù)的高可用、單節(jié)點(diǎn)可以存儲(chǔ)很多日志、IO隔離等優(yōu)勢(shì),針對(duì)這些特性在后文會(huì)展開(kāi)介紹。
3. BookKeeper的誕生
BookKeeper也是Apache的一個(gè)項(xiàng)目,同樣是由雅虎捐獻(xiàn)誕生,原本是為了應(yīng)對(duì)雅虎開(kāi)源HDFS里元數(shù)據(jù)存儲(chǔ)的需求。
下圖是字節(jié)跳動(dòng)技術(shù)文章的一個(gè)圖,主要是呈現(xiàn)在字節(jié)跳動(dòng)如何用BookKeeper支撐元數(shù)據(jù)服務(wù),支撐起EB級(jí)別的HDFS集群。這個(gè)集群DN有好幾萬(wàn)臺(tái),需要很多NameNode,就需要一個(gè)可以保障active/standby/observer NameNode之間強(qiáng)一致性的日志服務(wù),單機(jī)容量瓶頸下很難支撐這么大的體量時(shí),引入了一個(gè)分布式的日志服務(wù),這就是BookKeeper誕生的場(chǎng)景。隨著HDFS大規(guī)模的問(wèn)題開(kāi)始出現(xiàn)之后,BookKeeper成為了HDFS在HA上的剛需需求,例如在EMC內(nèi)部的HDFS集群,也是用的BookKeeper來(lái)做NameNode的editlog服務(wù)。BookKeeper是一種分布式場(chǎng)景下很常見(jiàn)的復(fù)制狀態(tài)機(jī)的實(shí)現(xiàn)(通過(guò)復(fù)制log,保持各個(gè)節(jié)點(diǎn)狀態(tài)機(jī)的同步,A節(jié)點(diǎn)持久化log后,把log同步到B節(jié)點(diǎn),在B節(jié)點(diǎn)進(jìn)行l(wèi)og的一個(gè)重放,讓B節(jié)點(diǎn)達(dá)到跟A節(jié)點(diǎn)一樣的一個(gè)狀態(tài))。由于在HDFS場(chǎng)景中,保存的只是NN的變更日志,所以算是元數(shù)據(jù)的元數(shù)據(jù),對(duì)數(shù)據(jù)一致性、對(duì)吞吐、對(duì)時(shí)延的要求自然極高。
4. BookKeeper使用案例
BookKeeper也有局限性,是append only的一個(gè)抽象變成了分布式服務(wù),相對(duì)而言比較底層。所以用戶多是一些比較大的互聯(lián)網(wǎng)公司或其他有大數(shù)據(jù)量的需求的用戶,這些用戶會(huì)在BookKeeper之上做一些二次開(kāi)發(fā),例如Pulsar在BookKeeper之上做了一層broker服務(wù),對(duì)BookKeeper的每個(gè)分片做一些管理然后將其作為數(shù)據(jù)的存儲(chǔ)服務(wù)。
類(lèi)似的還有Twitter和Salesforce。Twitter的技術(shù)棧是構(gòu)建在實(shí)時(shí)計(jì)算上的,在Twitter內(nèi)部,BookKeeper是作為很重要的基礎(chǔ)設(shè)施,不但有類(lèi)似Pulsar的服務(wù)eventbus,還有其他使用場(chǎng)景例如搜索、廣告、Stream computing, 以及作為類(lèi)似KV存儲(chǔ)的Manhattan Database的元數(shù)據(jù)服務(wù),這些場(chǎng)景都用到了BookKeeper。在規(guī)模上,Twitter BookKeeper有兩個(gè)集群,每個(gè)集群約有1500個(gè)節(jié)點(diǎn),每天有17PB的數(shù)據(jù),每秒1.5萬(wàn)億的records。而在Salesforce的使用背景,是Salesforce想去掉對(duì)Oracle的依賴,所以自研了類(lèi)似Amazon Aurora的NewSQL Database,其內(nèi)部很多跟元數(shù)據(jù)相關(guān)或有一致性要求的服務(wù)都是通過(guò)BookKeeper來(lái)滿足的,并且也有部分后端場(chǎng)景將BookKeeper作為存儲(chǔ)服務(wù)去用。
--
02 BookKeeper的特性
1. BookKeeper基本概念
- Ledger
可以理解為BookKeeper是會(huì)計(jì),Ledger是賬本,每個(gè)賬本是記錄信息的一個(gè)單元,寫(xiě)完之后轉(zhuǎn)為closed狀態(tài)(只讀),最新的賬本是打開(kāi)狀態(tài)(openLedger),以append only的方式持續(xù)存儲(chǔ)數(shù)據(jù)。
- Fragment
可以理解為BookKeeper內(nèi)部維護(hù)的一個(gè)以append only的方式添加的數(shù)據(jù)組。
Fragment之下就是用戶以append only的方式追加的一條條數(shù)據(jù)。
2. BookKeeper的節(jié)點(diǎn)對(duì)等架構(gòu)
openLedger時(shí)有3個(gè)參數(shù):Ensemble選擇幾個(gè)節(jié)點(diǎn)存儲(chǔ)這個(gè)賬本,Write Quorum控制數(shù)據(jù)寫(xiě)幾個(gè)副本(并發(fā)寫(xiě),不同于Kafka或HDFS,BookKeeper沒(méi)有數(shù)據(jù)節(jié)點(diǎn)之間主從同步的關(guān)系,把數(shù)據(jù)同步的協(xié)調(diào)者從服務(wù)端移到了客戶端),Ack Quorum控制等幾個(gè)副本返回ack。
以下圖為例openLedger(5,3,2),在保存這個(gè)賬本時(shí),選擇了5個(gè)節(jié)點(diǎn),但是只寫(xiě)3個(gè)副本,等2個(gè)副本來(lái)返回ack。第一個(gè)參數(shù)一般可用于調(diào)整并發(fā)度,因?yàn)閷?xiě)3個(gè)副本是通過(guò)輪轉(zhuǎn)的方式寫(xiě)入,例如第1個(gè)record是寫(xiě)1-3節(jié)點(diǎn),第2個(gè)record寫(xiě)2-4節(jié)點(diǎn),第3個(gè)record寫(xiě)3-5節(jié)點(diǎn),第4個(gè)record寫(xiě)4-5和1節(jié)點(diǎn)這樣輪轉(zhuǎn)。這種方式即便3個(gè)副本,也可以把5個(gè)節(jié)點(diǎn)都用起來(lái)。
這幾個(gè)參數(shù)便捷的特性可讓用戶通過(guò)機(jī)架感知、機(jī)房感知、resource感知等各種方式進(jìn)行靈活設(shè)置。當(dāng)選好節(jié)點(diǎn)后節(jié)點(diǎn)之間的排序就已完成,每個(gè)record會(huì)帶個(gè)index,index和節(jié)點(diǎn)已有綁定關(guān)系,例如index為1的,都放在123上,為2的都放在234上。通過(guò)這種方式可以讓我們知道每個(gè)節(jié)點(diǎn)存了哪些消息,當(dāng)某個(gè)節(jié)點(diǎn)宕機(jī),根據(jù)這個(gè)節(jié)點(diǎn)的位置信息,把對(duì)應(yīng)record還在哪些節(jié)點(diǎn)上有副本的信息找出來(lái)進(jìn)行多對(duì)多的恢復(fù)。這么做的另一個(gè)好處是不用再維護(hù)元數(shù)據(jù)信息,只需要有每個(gè)節(jié)點(diǎn)記錄index信息,在openLedger時(shí)記錄好每個(gè)節(jié)點(diǎn)的順序即可。
openLedger(5,3,2)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)就是下圖中右邊的結(jié)構(gòu),如果選擇Ensemble=3,Write Quorum=3,數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)就是下圖左邊的結(jié)構(gòu):
綜上,用戶可以通過(guò)Ensemble來(lái)調(diào)整讀寫(xiě)帶寬,通過(guò)Write Quorum調(diào)整強(qiáng)一致性的控制,通過(guò)Ack Quorum權(quán)衡在有較多副本時(shí)也可以有較低的長(zhǎng)尾時(shí)延(但一致性就可能有一定的損失)。
3. BookKeeper可用性
- 讀的高可用
讀的訪問(wèn)是對(duì)等的,任意一個(gè)節(jié)點(diǎn)返回就算讀成功。這個(gè)特性可以把延遲固定在一個(gè)閾值內(nèi),當(dāng)遇到網(wǎng)絡(luò)抖動(dòng)或壞節(jié)點(diǎn),通過(guò)延遲的參數(shù)避障。例如讀的延遲時(shí)間2ms,讀節(jié)點(diǎn)3超過(guò)2ms,就會(huì)并發(fā)地讀節(jié)點(diǎn)4,任意一個(gè)節(jié)點(diǎn)返回就算讀成功,如下圖Reader部分。
- 寫(xiě)的高可用
在openLedger時(shí)會(huì)記錄每個(gè)節(jié)點(diǎn)的順序,假如寫(xiě)到5節(jié)點(diǎn)宕機(jī),會(huì)做一次元數(shù)據(jù)的變更,從這個(gè)時(shí)間開(kāi)始,先進(jìn)行數(shù)據(jù)恢復(fù),同時(shí)新的index中會(huì)把5節(jié)點(diǎn)變?yōu)?節(jié)點(diǎn),如下圖x節(jié)點(diǎn)替換5節(jié)點(diǎn):
4. BookKeeper一致性
BookKeeper底層節(jié)點(diǎn)對(duì)等設(shè)計(jì)讓寫(xiě)入數(shù)據(jù)的Writer成為了協(xié)調(diào)者,Writer來(lái)保存數(shù)據(jù)是否存儲(chǔ)成功的狀態(tài),例如節(jié)點(diǎn)是否出現(xiàn)問(wèn)題、副本夠不夠、切換Fragment時(shí)要不要做數(shù)據(jù)恢復(fù)、在寫(xiě)入過(guò)程中出現(xiàn)宕機(jī)時(shí),通過(guò)fencing的方式防止腦裂等。所以,Writer維護(hù)了2個(gè)index:LastAddPushed和LastAddConfirmed。
LastAddPushed會(huì)隨消息ID遞增,LastAddConfirmed則記錄最后一個(gè)連續(xù)的消息成功寫(xiě)入了(例如Ack Quorum為2,有2個(gè)成功返回了即為成功),但因?yàn)榉祷仨樞虿灰欢ㄅc消息順序一致,例如123個(gè)消息,3的消息先返回了,2的還未返回,按連續(xù)的規(guī)則就是2不是3。
5. BookKeeper與Raft的對(duì)比
在底層原理上,Raft與BookKeeper有很多類(lèi)似的地方,Raft每個(gè)數(shù)據(jù)寫(xiě)入的組織形式是term,跟BookKeeper的segment類(lèi)似,每個(gè)term也會(huì)選擇一組節(jié)點(diǎn)存儲(chǔ)數(shù)據(jù),然后不斷往后追加數(shù)據(jù),通過(guò)數(shù)據(jù)節(jié)點(diǎn)之間的協(xié)同保證數(shù)據(jù)一致性。
在數(shù)據(jù)結(jié)構(gòu)上,Raft在保存數(shù)據(jù)時(shí)有Entry,Entry除了帶本身的index還會(huì)帶上last committed index,與BookKeeper中的LastAddConfirmed較為類(lèi)似,只是BK是通過(guò)Writer來(lái)協(xié)調(diào)數(shù)據(jù)在不同節(jié)點(diǎn)的一致性,Raft有l(wèi)eader來(lái)協(xié)調(diào)數(shù)據(jù)在不同節(jié)點(diǎn)的一致性。
6. BookKeeper的IO讀寫(xiě)分離
下圖是每個(gè)數(shù)據(jù)節(jié)點(diǎn)的數(shù)據(jù)流轉(zhuǎn)過(guò)程,數(shù)據(jù)寫(xiě)入時(shí),Writer通過(guò)append only方式寫(xiě)入到Journal,Journal在把數(shù)據(jù)寫(xiě)到內(nèi)存的同時(shí)會(huì)按一定頻率(默認(rèn)1ms或500 byte)把數(shù)據(jù)持久化到Journal Device里,寫(xiě)完后會(huì)告訴Writer這個(gè)節(jié)點(diǎn)寫(xiě)入成功了(持久化到磁盤(pán)是默認(rèn)配置)。
Journal在數(shù)據(jù)寫(xiě)入時(shí)有寫(xiě)到內(nèi)存中,接下來(lái)在內(nèi)存中做排序(用于解決如果按寫(xiě)的順序讀會(huì)導(dǎo)致分區(qū)隨機(jī)性強(qiáng)的問(wèn)題),然后把數(shù)據(jù)刷到數(shù)據(jù)盤(pán)中。讀的時(shí)候,如果讀最新的數(shù)據(jù),可以直接從內(nèi)存里返回,如果讀歷史數(shù)據(jù),也只去讀數(shù)據(jù)盤(pán),不會(huì)對(duì)Journal Device寫(xiě)入有影響。這樣針對(duì)有讀瓶頸或?qū)懫款i的用戶,可以把Journal Disk或Ledger Disk換成SSD盤(pán),提升性能,并且防止讀寫(xiě)的互相干擾。
--
03 BookKeeper的存儲(chǔ)介質(zhì)演變
1. BookKeeper的Disk演進(jìn)
在演進(jìn)過(guò)程中,因?yàn)轫樞蜃x的情況比較多,所以讀的部分變化不大,但在寫(xiě)的這部分經(jīng)歷了HDD到SSD再到NVMe SSD,再到現(xiàn)在部分用戶換成了Intel的PMem的過(guò)程(如下圖所示)。在換到NVMe SSD時(shí),部分用戶通過(guò)多目錄的方式可以把SSD的IO帶寬打的很滿。
2. PMEM在BookKeeper上的應(yīng)用
PMem的特性非常匹配Journal Disk,單塊PMem可以達(dá)到3-4GB的帶寬,不但能提供高帶寬吞吐而且可持久化。PMem容量相比SSD比較小、相比內(nèi)存又比較大,在剛推出時(shí)單條128GB,有著GB級(jí)別的吞吐和ns級(jí)別的延遲。
高吞吐低容量的PMem非常適合Journal持久話刷盤(pán)的需求,例如宕機(jī)后,需要對(duì)沒(méi)刷到磁盤(pán)的這部分?jǐn)?shù)據(jù)做恢復(fù),需要Journal做replay log重放,由于只是增量日志而非全量數(shù)據(jù),所以并不需要很大的容量,正好和PMem容量不大相匹配。而且,PMem的壽命會(huì)比SSD的壽命長(zhǎng)一些,例如在每天同樣寫(xiě)入量下SSD可能只能用1年而PMem預(yù)計(jì)可以使用4-5年。
雅虎(現(xiàn)在是Verizon Media)有實(shí)際通過(guò)PMEem優(yōu)化BookKeeper的案例,在只增加5%的單機(jī)成本情況下提升了5倍的帶寬吞吐和低于5ms的時(shí)延保障(BookKeeper社區(qū)與Intel正在合作做性能測(cè)試,預(yù)計(jì)未來(lái)會(huì)產(chǎn)出白皮書(shū)說(shuō)明)。
在雅虎案例中用10臺(tái)Pulsar(底層是用PMem做Journal Disk的BookKeeper)替換了33臺(tái)Kafka,比原Kafka方案成本降低了一半,產(chǎn)出的對(duì)比結(jié)果如下:
--
04 社區(qū)資源
- 團(tuán)隊(duì)構(gòu)成
由Apache Pulsar核心研發(fā)團(tuán)隊(duì)創(chuàng)立,同時(shí)有Apache Pulsar和Apache BookKeeper項(xiàng)目管理委員會(huì)(PMC)主席,有6名Apache Pulsar PMC成員和3名Apache BookKeeper PMC成員,有約20名 Apache Committer。
- 里程碑
公司成立于2019年,2020年發(fā)布商業(yè)化產(chǎn)品StreamNative Cloud,目前有50+付費(fèi)客戶,覆蓋金融、IoT、互聯(lián)網(wǎng)、制造多個(gè)行業(yè)。
- 優(yōu)勢(shì)
是社區(qū)和代碼的構(gòu)建維護(hù)者,有全球最專(zhuān)業(yè)的Pulsar設(shè)計(jì)開(kāi)發(fā)、運(yùn)維、管理團(tuán)隊(duì)的7*24小時(shí)服務(wù),提供開(kāi)箱即用的云服務(wù)和咨詢培訓(xùn)服務(wù)。
今天的分享就到這里,謝謝大家。
分享嘉賓:
本文首發(fā)于微信公眾號(hào)“DataFunTalk”。
總結(jié)
以上是生活随笔為你收集整理的翟佳:高可用、强一致、低延迟——BookKeeper的存储实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Java设计模式】——单例模式
- 下一篇: TF卡里删掉文件后内存没变大_不用第三方