過去的一年多的時(shí)間中,大部分的工作都圍繞著Zeppelin這個(gè)項(xiàng)目展開,經(jīng)歷了Zeppelin的從無到有,再到逐步完善穩(wěn)定。見證了Zeppelin的成長(zhǎng)的同時(shí),Zeppelin也見證了我的積累進(jìn)步。對(duì)我而言,Zeppelin就像是孩提時(shí)代一同長(zhǎng)大的朋友,在無數(shù)次的游戲和談話中,交換對(duì)未知世界的感知,碰撞對(duì)未來的憧憬,然后刻畫出更好的彼此。這篇博客中就向大家介紹下我的這位老朋友。
武都ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!定位
Zeppelin是一個(gè)分布式的KV存儲(chǔ)平臺(tái),在設(shè)計(jì)之初,我們對(duì)他有如下幾個(gè)主要期許:
高性能;
大集群,因此需要有更好的可擴(kuò)展性和必要的業(yè)務(wù)隔離及配額;
作為支撐平臺(tái),向上支撐更豐富的協(xié)議;
Zeppelin的整個(gè)設(shè)計(jì)和實(shí)現(xiàn)都圍繞這三個(gè)目標(biāo)努力,本文將從API、數(shù)據(jù)分布、元信息管理、一致性、副本策略、數(shù)據(jù)存儲(chǔ)、故障檢測(cè)幾個(gè)方面來分別介紹。
為了讓讀者對(duì)Zeppelin有個(gè)整體印象,先介紹下其提供的接口:
基本的KV存儲(chǔ)相關(guān)接口:Set、Get、Delete;
支持TTL;
HashTag及針對(duì)同一HashTag的Batch操作,Batch保證原子,這一支持主要是為了支撐上層更豐富的協(xié)議。
最為一個(gè)分布式存儲(chǔ),首要需要解決的就是數(shù)據(jù)分布的問題。另一篇博客淺談分布式存儲(chǔ)系統(tǒng)數(shù)據(jù)分布方法中介紹了可能的數(shù)據(jù)分布方案,Zeppelin選擇了比較靈活的分片的方式,如下圖所示:
用邏輯概念Table區(qū)分業(yè)務(wù),并將Table的整個(gè)Key Space劃分為相同大小的分片(Partition),每個(gè)分片的多副本分別存儲(chǔ)在不同的存儲(chǔ)節(jié)點(diǎn)(Node Server)上,因而,每個(gè)Node Server都會(huì)承載多個(gè)Partition的不同副本。Partition個(gè)數(shù)在Table創(chuàng)建時(shí)確定,更多的Partition數(shù)會(huì)帶來更好的數(shù)據(jù)均衡效果,提供擴(kuò)展到更大集群的可能,但也會(huì)帶來元信息膨脹的壓力。實(shí)現(xiàn)上,Partition又是數(shù)據(jù)備份、數(shù)據(jù)遷移、數(shù)據(jù)同步的最小單位,因此更多的Partition可能帶來更多的資源壓力。Zeppelin的設(shè)計(jì)實(shí)現(xiàn)上也會(huì)盡量降低這種影響。
可以看出,分片的方式將數(shù)據(jù)分布問題拆分為兩層隱射:從Key到Partition的映射可以簡(jiǎn)單的用Hash實(shí)現(xiàn)。而Partition副本到存儲(chǔ)節(jié)點(diǎn)的映射相對(duì)比較復(fù)雜,需要考慮穩(wěn)定性、均衡性、節(jié)點(diǎn)異構(gòu)及故障域隔離(更多討論見淺談分布式存儲(chǔ)系統(tǒng)數(shù)據(jù)分布方法)。關(guān)于這一層映射,Zeppelin的實(shí)現(xiàn)參考了CRUSH對(duì)副本故障域的層級(jí)維護(hù)方式,但擯棄了CRUSH對(duì)降低元信息量稍顯偏執(zhí)的追求。
在進(jìn)行創(chuàng)建Table、擴(kuò)容、縮容等集群變化的操作時(shí),用戶需要提供整個(gè):
集群分層部署的拓?fù)湫畔ⅲò?jié)點(diǎn)的機(jī)架、機(jī)器等部署信息);
存儲(chǔ)節(jié)點(diǎn)權(quán)重;
各個(gè)故障層級(jí)的分布規(guī)則;
Zeppelin根據(jù)這些信息及當(dāng)前的數(shù)據(jù)分布直接計(jì)算出完整的目標(biāo)數(shù)據(jù)分布,這個(gè)過程會(huì)盡量保證數(shù)據(jù)均衡及需要的副本故障域。下圖舉例展示了,副本在機(jī)架(cabinet)級(jí)別隔離的規(guī)則及分布方式。更詳細(xì)的介紹見Decentralized Placement of Replicated Data
上面確定了分片的數(shù)據(jù)分布方式,可以看出,包括各個(gè)分片副本的分布情況在內(nèi)的元信息需要在整個(gè)集群間共享,并且在變化時(shí)及時(shí)擴(kuò)散,這就涉及到了元信息管理的問題,通常有兩種方式:
有中心的元信息管理:由中心節(jié)點(diǎn)來負(fù)責(zé)整個(gè)集群元信息的檢測(cè)、更新和維護(hù),這種方式的優(yōu)點(diǎn)是設(shè)計(jì)簡(jiǎn)潔清晰,容易實(shí)現(xiàn),且元信息傳播總量相對(duì)較小并且及時(shí)。大的缺點(diǎn)就是中心節(jié)點(diǎn)的單點(diǎn)故障。以BigTable和Ceph為代表。
對(duì)等的元信息管理:將集群元信息的處理負(fù)擔(dān)分散到集群的所有節(jié)點(diǎn)上去,節(jié)點(diǎn)間地位一致。元信息變動(dòng)時(shí)需要采用Gossip等協(xié)議來傳播,限制了集群規(guī)模。而無單點(diǎn)故障和較好的水平擴(kuò)展能力是它的主要優(yōu)點(diǎn)。Dynamo和Redis Cluster采用的是這種方式。
考慮到對(duì)大集群目標(biāo)的需求,Zeppelin采用了有中心節(jié)點(diǎn)的元信息管理方式。其整體結(jié)構(gòu)如下圖所示:
可以看出Zeppelin有三個(gè)主要的角色,元信息節(jié)點(diǎn)Meta Server、存儲(chǔ)節(jié)點(diǎn)Node Server及Client。Meta負(fù)責(zé)元信息的維護(hù)、Node的存活檢測(cè)及元信息分發(fā);Node負(fù)責(zé)實(shí)際的數(shù)據(jù)存儲(chǔ);Client的首次訪問需要先從Meta獲得當(dāng)前集群的完整數(shù)據(jù)分布信息,對(duì)每個(gè)用戶請(qǐng)求計(jì)算正確的Node位置,并發(fā)起直接請(qǐng)求。
為了減輕上面提到的中心節(jié)點(diǎn)的單點(diǎn)問題。我們采取了如下策略:
Meta Server以集群的方式提供服務(wù),之間以一致性算法來保證數(shù)據(jù)正確。
良好的Meta設(shè)計(jì):包括一致性數(shù)據(jù)的延遲提交;通過Lease讓Follower分擔(dān)讀請(qǐng)求;粗粒度的分布式鎖實(shí)現(xiàn);合理的持久化及臨時(shí)數(shù)據(jù)劃分等。更詳細(xì)的介紹見:Zeppelin不是飛艇之元信息節(jié)點(diǎn)
智能Client:Client承擔(dān)更多的責(zé)任,比如緩存元信息;維護(hù)到Node Server的鏈接;計(jì)算數(shù)據(jù)分布的初始及變化。
Node Server分擔(dān)更多責(zé)任:如元信息更新由存儲(chǔ)節(jié)點(diǎn)發(fā)起;通過MOVE,WAIT等信息,實(shí)現(xiàn)元信息變化時(shí)的客戶端請(qǐng)求重定向,減輕Meta壓力。更詳細(xì)的介紹見:Zeppelin不是飛艇之存儲(chǔ)節(jié)點(diǎn)
通過上面幾個(gè)方面的策略設(shè)計(jì),盡量的降低對(duì)中心節(jié)點(diǎn)的依賴。即使Meta集群整個(gè)異常時(shí),已有的客戶端請(qǐng)求依然能正常進(jìn)行。
上面已經(jīng)提到,中心元信息Meta節(jié)點(diǎn)以集群的方式進(jìn)行服務(wù)。這就需要一致性算法來保證:
即使發(fā)生網(wǎng)絡(luò)分區(qū)或節(jié)點(diǎn)異常,整個(gè)集群依然能夠像單機(jī)一樣提供一致的服務(wù),即下一次的成功操作可以看到之前的所有成功操作按順序完成。
Zeppelin中采用了我們的一致性庫Floyd來完成這一目標(biāo),F(xiàn)loyd是Raft的C++實(shí)現(xiàn)。更多內(nèi)容可以參考:Raft和它的三個(gè)子問題。
利用一致性協(xié)議,Meta集群需要完成Node節(jié)點(diǎn)的存活檢測(cè)、元信息更新及元信息擴(kuò)散等任務(wù)。這里需要注意的是,由于一致性算法的性能相對(duì)較低,我們需要控制寫入一致性庫的數(shù)據(jù),只寫入重要、不易恢復(fù)且修改頻度較低的數(shù)據(jù)。
為了容錯(cuò),通常采用數(shù)據(jù)三副本的方式,又由于對(duì)高性能的定位,我們選擇了Master,Slave的副本策略。每個(gè)Partition包含至少三個(gè)副本,其中一個(gè)為Master,其余為Slave。所有的用戶請(qǐng)求由Master副本負(fù)責(zé),讀寫分離的場(chǎng)景允許Slave也提供讀服務(wù)。Master處理的寫請(qǐng)求會(huì)在修改DB后寫B(tài)inlog,并異步的將Binlog同步給Slave。
上圖所示的是Master,Slave之間建立主從關(guān)系的過程,右邊為Slave。當(dāng)元信息變化時(shí),Node從Meta拉取最新的元信息,發(fā)現(xiàn)自己是某個(gè)Partition新的Slave時(shí),將TrySync任務(wù)通過Buffer交給TrySync Moudle;TrySync Moudle向Master的Command Module發(fā)起Trysync;Master生成Binlog Send任務(wù)到Send Task Pool;Binlog Send Module向Slave發(fā)送Binlog,完成數(shù)據(jù)異步復(fù)制。更詳細(xì)內(nèi)容見:Zeppelin不是飛艇之存儲(chǔ)節(jié)點(diǎn)。未來也考慮支持Quorum及EC的副本方式來滿足不同的使用場(chǎng)景。
Node Server最終需要完成數(shù)據(jù)的存儲(chǔ)及查詢等操作。Zeppelin目前采用了Rocksdb作為存儲(chǔ)引擎,每個(gè)Partition副本都會(huì)占有獨(dú)立的Rocksdb實(shí)例。采用LSM方案也是為了對(duì)高性能的追求,相對(duì)于B+Tree,LSM通過將隨機(jī)寫轉(zhuǎn)換為順序?qū)懘蠓嵘藢懶阅?,同時(shí),通過內(nèi)存緩存保證了相對(duì)不錯(cuò)的讀性能。庖丁解LevelDB之概覽中以LevelDB為例介紹了LSM的設(shè)計(jì)和實(shí)現(xiàn)。
然而,在數(shù)據(jù)Value較大的場(chǎng)景下,LSM寫放大問題嚴(yán)重。為了高性能,Zeppelin大多采用SSD盤,SSD的隨機(jī)寫和順序?qū)懼g的差距并不像機(jī)械盤那么大,同時(shí)SSD又有擦除壽命的問題,因此LSM通過多次重復(fù)寫換來的高性能優(yōu)勢(shì)不太劃算。而Zeppelin需要對(duì)上層不同協(xié)議的支撐,又不可避免的會(huì)出現(xiàn)大Value,LSM upon SSD針對(duì)這方面做了更多的討論,包括這種改進(jìn)在內(nèi)的其他針對(duì)不同場(chǎng)景的存儲(chǔ)引擎及可插拔的設(shè)計(jì)也是Zeppelin未來的發(fā)展方向。
一個(gè)好的故障檢測(cè)的機(jī)制應(yīng)該能做到如下幾點(diǎn):
及時(shí):節(jié)點(diǎn)發(fā)生異常如宕機(jī)或網(wǎng)絡(luò)中斷時(shí),集群可以在可接受的時(shí)間范圍內(nèi)感知;
適當(dāng)?shù)膲毫?/strong>:包括對(duì)節(jié)點(diǎn)的壓力,和對(duì)網(wǎng)絡(luò)的壓力;
容忍網(wǎng)絡(luò)抖動(dòng)
擴(kuò)散機(jī)制:節(jié)點(diǎn)存活狀態(tài)改變導(dǎo)致的元信息變化需要通過某種機(jī)制擴(kuò)散到整個(gè)集群;
Zeppelin 中的故障可能發(fā)生在元信息節(jié)點(diǎn)集群或存儲(chǔ)節(jié)點(diǎn)集群,元信息節(jié)點(diǎn)集群的故障檢測(cè)依賴下層的Floyd的Raft實(shí)現(xiàn),并且在上層通過Jeopardy階段來容忍抖動(dòng)。更詳細(xì)內(nèi)容見:Zeppelin不是飛艇之元信息節(jié)點(diǎn)。
而存儲(chǔ)節(jié)點(diǎn)的故障檢測(cè)由元信息節(jié)點(diǎn)負(fù)責(zé), 感知到異常后,元信息節(jié)點(diǎn)集群修改元信息、更新元信息版本號(hào),并通過心跳通知所有存儲(chǔ)節(jié)點(diǎn),存儲(chǔ)節(jié)點(diǎn)發(fā)現(xiàn)元信息變化后,主動(dòng)拉去最新元信息并作出相應(yīng)改變。
最后,Zeppelin還提供了豐富的運(yùn)維、監(jiān)控?cái)?shù)據(jù),以及相關(guān)工具。方便通過Prometheus等工具監(jiān)控展示。
[Zeppelin](https://github.com/Qihoo360/zeppelin)
[Floyd](https://github.com/Qihoo360/floyd)
[Raft](https://raft.github.io/)
[淺談分布式存儲(chǔ)系統(tǒng)數(shù)據(jù)分布方法](http://catkang.github.io/2017/12/17/data-placement.html)
[Decentralized Placement of Replicated Data](https://whoiami.github.io/DPRD)
[Zeppelin不是飛艇之元信息節(jié)點(diǎn)](http://catkang.github.io/2018/01/19/zeppelin-meta.html)
[Zeppelin不是飛艇之存儲(chǔ)節(jié)點(diǎn)](http://catkang.github.io/2018/01/07/zeppelin-overview.html)
[Raft和它的三個(gè)子問題](http://catkang.github.io/2017/06/30/raft-subproblem.html)
[庖丁解LevelDB之概覽](http://catkang.github.io/2017/01/07/leveldb-summary.html)
[LSM upon SSD](http://catkang.github.io/2017/04/30/lsm-upon-ssd.html)
原文鏈接:https://mp.weixin.qq.com/s/cfMtQ1YAZiCId3OM7bxXrg