LogDevice:來自Facebook的分布式日志數(shù)據(jù)存儲(chǔ)系統(tǒng)

大數(shù)據(jù)

作者:麥克周?

寫在前面

做過分布式系統(tǒng)的人都知道,想要在大規(guī)模集群下處理高并發(fā)事務(wù)時(shí)同時(shí)滿足CAP(一致性、可用性、分區(qū)容錯(cuò)),從理論上來說不可能,當(dāng)然聽說最近谷歌已經(jīng)實(shí)現(xiàn)了這樣的分布式系統(tǒng),但是總的來說確實(shí)非常難。對(duì)于社交媒體的海量日志文件,如果我們也提出了需要確保高可用、持續(xù)寫入數(shù)據(jù)、按照記錄順序返回?cái)?shù)據(jù)等三條要求,你覺得是否可以實(shí)現(xiàn)?FaceBook的LogDevice實(shí)現(xiàn)了。

什么是日志

日志是記錄一系列序列化的系統(tǒng)行為的信息,我們需要確保它們能夠被保存在可靠的地方。對(duì)于應(yīng)用程序來說,日志的作用一般有兩個(gè),即Troubleshooting和顯示程序運(yùn)行狀態(tài)。好的日志記錄方式可以提供我們足夠多定位問題的依據(jù)。對(duì)于一些復(fù)雜系統(tǒng),例如數(shù)據(jù)庫,日志可以承擔(dān)數(shù)據(jù)備份、同步作用,很多分布式數(shù)據(jù)庫都采用“write-ahead”方案,在節(jié)點(diǎn)數(shù)據(jù)同步時(shí)通過日志文件恢復(fù)數(shù)據(jù)。

日志一般具有三個(gè)特性:

面向記錄:寫入日志的一定是孤立的行,而不是一個(gè)字節(jié)。日志實(shí)質(zhì)上是問題的最小單元,用戶也一定是讀取整行日志。日志的存儲(chǔ)原則上按照順序,即按照LSN(日志順序數(shù)字)存放,但是也不完全這么要求,所以日志系統(tǒng)可以優(yōu)先高寫入需求,對(duì)寫入失敗容錯(cuò)。日志天生就是遞增的:也就是說,日志是不會(huì)修改的,那么也就意味著,日志系統(tǒng)的設(shè)計(jì)應(yīng)該是以高寫入、高讀取為目標(biāo),不需要擔(dān)心更新操作的數(shù)據(jù)一致性問題。日志存儲(chǔ)周期長:可能是一天,也可能是一個(gè)月,甚至于一年。這也就意味著,日志的刪除規(guī)則一般都是按照時(shí)間或者空間進(jìn)行設(shè)定的,具有固定的規(guī)則。

來個(gè)假如

假如我們要設(shè)計(jì)一個(gè)分布式日志存儲(chǔ)系統(tǒng),你會(huì)怎么設(shè)計(jì)?

日志信息需要傳輸、存儲(chǔ),為了實(shí)現(xiàn)穩(wěn)定的數(shù)據(jù)交換,我們可以采用Kafka作為消息中間件。

Kafka實(shí)際上是一個(gè)消息發(fā)布訂閱系統(tǒng)。Producer向某個(gè)Topic發(fā)布消息,而Consumer訂閱某個(gè)Topic的消息,進(jìn)而一旦有新的關(guān)于某個(gè)Topic的消息,Broker會(huì)傳遞給訂閱它的所有Consumer。在Kafka中,消息是按Topic組織的,而每個(gè)Topic又會(huì)分為多個(gè)Partition,這樣便于管理數(shù)據(jù)和進(jìn)行負(fù)載均衡。同時(shí),它也使用了Zookeeper進(jìn)行負(fù)載均衡。

Kafka在磁盤上的存取代價(jià)為O(1),即便是普通服務(wù)器,每秒也能處理幾十萬條消息,并且它本身就是分布式架構(gòu),也支持將數(shù)據(jù)并行加載到Hadoop。

大數(shù)據(jù)

上面這張圖是一個(gè)典型的采用消息中間件進(jìn)行日志數(shù)據(jù)交換的系統(tǒng)設(shè)計(jì)架構(gòu),但是沒有實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ),也沒有描述數(shù)據(jù)是如何被抽取并發(fā)送到Kafka的。

如果想要實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ),并描述清楚內(nèi)部處理流程,我們可以采用怎么樣的日志處理系統(tǒng)架構(gòu)呢?這里推薦你FaceBook的Scribe,它是一款開源的日志收集系統(tǒng),在Facebook內(nèi)部已經(jīng)得到大量的應(yīng)用。它能夠從各種日志源上收集日志,存儲(chǔ)到一個(gè)中央存儲(chǔ)系統(tǒng) (可以是NFS,分布式文件系統(tǒng)等)上,以便于進(jìn)行集中統(tǒng)計(jì)分析處理。

Scribe最重要的特點(diǎn)是容錯(cuò)性好。當(dāng)后端的存儲(chǔ)系統(tǒng)奔潰時(shí),Scribe會(huì)將數(shù)據(jù)寫到本地磁盤上,當(dāng)存儲(chǔ)系統(tǒng)恢復(fù)正常后,Scribe將日志重新加載到存儲(chǔ)系統(tǒng)中。

大數(shù)據(jù)

Scribe的架構(gòu)比較簡單,主要包括三部分,分別為Scribe Agent, Scribe和存儲(chǔ)系統(tǒng)。Scribe Agent實(shí)際上是一個(gè)Thrift Client。Scribe接收到Thrift Client發(fā)送過來的數(shù)據(jù),根據(jù)配置文件,將不同topic的數(shù)據(jù)發(fā)送給不同的對(duì)象。存儲(chǔ)系統(tǒng)實(shí)際上就是Scribe中的Store,當(dāng)前Scribe支持非常多的Store。

貌似市面上已經(jīng)有很多分布式日志收集系統(tǒng)了,為什么FaceBook還需要推出LogDevice呢?而且FaceBook自己已經(jīng)有了Scribe,為什么還要繼續(xù)設(shè)計(jì)LogDevice?因?yàn)镾cribe更多實(shí)現(xiàn)了日志數(shù)據(jù)的收集,它不是一個(gè)完整的日志處理、存儲(chǔ)、讀取服務(wù),系統(tǒng)設(shè)計(jì)也較為死板,存儲(chǔ)更多依賴HDFS,使用過程中一定出現(xiàn)了不能滿足自身需求的情況。而對(duì)于開源的哪些分布式日志收集系統(tǒng),更多的是集成各個(gè)開源組件,共同完成日志存儲(chǔ)系統(tǒng)設(shè)計(jì)需求。對(duì)于FaceBook的工程師來說,他們一貫秉承著用于創(chuàng)新的精神,想想Apache Cassandra,其實(shí)當(dāng)時(shí)已經(jīng)有HBase等成熟的NoSQL數(shù)據(jù)庫,但是由于存在中心節(jié)點(diǎn)等諸多設(shè)計(jì)上的限制,F(xiàn)aceBook自己搞了一個(gè)全新的無中心化設(shè)計(jì)的架構(gòu),即便在初期飽受質(zhì)疑,后續(xù)也在不斷地改進(jìn),到目前為止,Cassandra真正進(jìn)入到了它的黃金時(shí)代。

LogDevice

設(shè)計(jì)背景

FaceBook擁有大量的分布式服務(wù)用于保存和處理數(shù)據(jù),如果想要構(gòu)建高可用的數(shù)據(jù)密集型分布式服務(wù),F(xiàn)aceBook認(rèn)為,一定需要保存日志。為了處理FaceBook內(nèi)部日志的高強(qiáng)度負(fù)載、性能需求,F(xiàn)aceBook把LogDevice設(shè)計(jì)成了可以調(diào)節(jié)的系統(tǒng),而不是一套方案應(yīng)對(duì)所有需求。

需求整理

對(duì)于日志服務(wù)的需求,也就是對(duì)于LogDevice的需求,第一條就是服務(wù)必須永遠(yuǎn)在線,不允許出現(xiàn)離線狀態(tài),因?yàn)镕aceBook內(nèi)部各個(gè)系統(tǒng)都需要保存日志,也就是說高可用。第二條是持久性,也就是說不允許丟數(shù)據(jù),特別是返回客戶端寫入成功之后,絕對(duì)不能丟失數(shù)據(jù)。第三條是存在一定程度的數(shù)據(jù)讀取,并且通常是讀取最近寫入的日志數(shù)據(jù),這一條實(shí)質(zhì)上是要求寫入響應(yīng)快。

設(shè)計(jì)思路

對(duì)于整個(gè)日志系統(tǒng)來說,整個(gè)設(shè)計(jì)應(yīng)該更加關(guān)注數(shù)據(jù)的寫入速度,怎么樣設(shè)計(jì)才能具有更快的寫入速度,并能支撐一定的讀取速度,所以需要看看數(shù)據(jù)是如何被寫入到LogDevice的。

如果需要提升日志文件的寫入速率,或者更高一點(diǎn)要求,希望沒有寫入速率限制,你該怎么實(shí)現(xiàn)?我們可以模仿分布式文件系統(tǒng)或者分布式數(shù)據(jù)庫的設(shè)計(jì)方式,采用多處副本方式,即一個(gè)文件有多個(gè)副本,那么每次日志寫入請(qǐng)求就有了幾處寫入地址選擇,而不是單一一個(gè)節(jié)點(diǎn),或者幾個(gè)特定的節(jié)點(diǎn)。這樣做的好處是,當(dāng)集群中的一部分節(jié)點(diǎn)宕機(jī)或者失去聯(lián)系時(shí),日志寫入請(qǐng)求不會(huì)受到大規(guī)模的干擾,并且寫入負(fù)載能夠做到相對(duì)均衡。

大數(shù)據(jù)

數(shù)據(jù)副本設(shè)計(jì),有沒有其他系統(tǒng)實(shí)現(xiàn)?

有,非常多,例如HDFS、Cassandra。我們這里還是以FaceBook自己出品的Cassandra為例。

Cassandra在多個(gè)節(jié)點(diǎn)上存儲(chǔ)副本以確??捎眯院蛿?shù)據(jù)容錯(cuò)。副本策略決定了副本的放置方法。集群中的副本數(shù)量被稱為復(fù)制因子,復(fù)制因子為1表示每行只有一個(gè)副本,復(fù)制因子為2表示每行有兩個(gè)副本,每個(gè)副本不在同一個(gè)節(jié)點(diǎn)。所有副本同等重要,沒有主次之分。作為一般規(guī)則,副本因子不應(yīng)超過在集群中的節(jié)點(diǎn)的樹木。當(dāng)副本因子超過節(jié)點(diǎn)數(shù)時(shí),寫入不會(huì)成功,但讀取只要提供所期望的一致性級(jí)別即可滿足。目前Cassandra中實(shí)現(xiàn)了不同的副本策略,包括:

SimpleStrategy:復(fù)制數(shù)據(jù)副本到協(xié)調(diào)者節(jié)點(diǎn)的N-1個(gè)后繼節(jié)點(diǎn)上;NetworkTopologyStrategy:用于多數(shù)據(jù)中心部署。這種策略可以指定每個(gè)數(shù)據(jù)中心的副本數(shù)。在同數(shù)據(jù)中心中,它按順時(shí)針方向直到另一個(gè)機(jī)架放置副本。它嘗試著將副本放置在不同的機(jī)架上,因?yàn)橥粰C(jī)架經(jīng)常因?yàn)殡娫?、制冷和網(wǎng)絡(luò)問題導(dǎo)致不可用。

多數(shù)據(jù)中心集群最常見的兩種配置方式是:

每個(gè)數(shù)據(jù)中心2個(gè)副本:此配置容忍每個(gè)副本組單節(jié)點(diǎn)的失敗,并且仍滿足一致性級(jí)別為ONE的讀操作。每個(gè)數(shù)據(jù)中心3個(gè)副本:此配置可以容忍在強(qiáng)一致性級(jí)別LOCAL_QUORUM基礎(chǔ)上的每個(gè)副本組1個(gè)節(jié)點(diǎn)的失敗,或者容忍一致性級(jí)別ONE的每個(gè)數(shù)據(jù)中心多個(gè)節(jié)點(diǎn)的失敗。

LogDevice將日志里的記錄順序和實(shí)際存儲(chǔ)的順序區(qū)分開來,通過序列器產(chǎn)生一個(gè)學(xué)號(hào),對(duì)每一行存儲(chǔ)的日志進(jìn)行重新序列標(biāo)定。一旦一行記錄被標(biāo)定了這個(gè)序列號(hào),接下來該條記錄(數(shù)據(jù))就會(huì)被保存在集群中任一位置。注意,這里提到的序列號(hào)不是一個(gè)數(shù)字,而是一對(duì)數(shù)字,第一個(gè)數(shù)字叫做“ epoch number”,第二個(gè)是相對(duì)于第一個(gè)的偏移量。序列號(hào)生成器本身也是需要做好容災(zāi)的,也就是說,一旦一個(gè)序列號(hào)生成器服務(wù)不在線,另一個(gè)一定要被立即啟用,而它生成的序列號(hào)要比當(dāng)前已經(jīng)存在的序列號(hào)大。FaceBook使用ZooKeeper保存序列號(hào)(Epoch Number)。

這里為什么要選擇ZooKeeper存儲(chǔ)序列號(hào)?

ZooKeeper作為Hadoop
項(xiàng)目中的一個(gè)子項(xiàng)目,是Hadoop集群管理的一個(gè)必不可少的模塊,它主要用來控制集群中的數(shù)據(jù),如它管理Hadoop集群中的NameNode,還有HBase中Master節(jié)點(diǎn)的選舉機(jī)制、服務(wù)器之間的狀態(tài)同步等。除此之外,ZooKeeper還可以被用在構(gòu)建高可用性集群、統(tǒng)一命名服務(wù)管理、分布式緩存機(jī)制設(shè)計(jì)、配置文件管理、集群管理、分布式鎖機(jī)制設(shè)計(jì)、隊(duì)列管理等等。

存儲(chǔ)序列號(hào)的思路配置文件管理類似。

配置文件的管理在分布式應(yīng)用環(huán)境中很常見,例如同一個(gè)應(yīng)用系統(tǒng)需要多臺(tái)PC Server運(yùn)行,但是它們運(yùn)行的應(yīng)用系統(tǒng)的某些配置項(xiàng)是相同的,如果要修改這些相同的配置項(xiàng),那么就必須同時(shí)修改每臺(tái)運(yùn)行這個(gè)應(yīng)用系統(tǒng)的PC Server,這樣非常麻煩而且容易出錯(cuò)。諸如這樣的配置信息完全可以交給ZooKeeper來管理,將配置信息保存在ZooKeeper的某個(gè)目錄節(jié)點(diǎn)中,然后將所有需要修改的應(yīng)用機(jī)器監(jiān)控配置信息的狀態(tài),一旦配置信息發(fā)生變化,每臺(tái)應(yīng)用機(jī)器就會(huì)收到ZooKeeper的通知,然后從ZooKeeper獲取新的配置信息應(yīng)用到系統(tǒng)中。

大數(shù)據(jù)

如上圖所示,實(shí)際應(yīng)用時(shí)我們可以通過自動(dòng)監(jiān)測Master節(jié)點(diǎn)內(nèi)是否形成了新的配置文件,并在檢測到形成了新的配置文件后主動(dòng)上傳到ZooKeeper,并下發(fā)到各Slave節(jié)點(diǎn)加載到內(nèi)存中用于搜索任務(wù)的處理,無需管理人員在發(fā)現(xiàn)Master節(jié)點(diǎn)形成了新的配置文件之后,重啟Master節(jié)點(diǎn)才將新的配置文件上傳,顯然降低了Master節(jié)點(diǎn)與Slave節(jié)點(diǎn)間配置文件同步的繁瑣性,提高了設(shè)備的智能性,降低了同步成本。

根據(jù)FaceBook的設(shè)計(jì)思路,由于日志文件本身是可以隨機(jī)讀的,并且很多節(jié)點(diǎn)上都存在數(shù)據(jù),這有點(diǎn)像小文件存儲(chǔ)方式,每個(gè)節(jié)點(diǎn)上的數(shù)據(jù)都可以被讀取,因此不會(huì)造成IO和網(wǎng)絡(luò)資源的浪費(fèi)。

數(shù)據(jù)是怎么做到負(fù)載均衡的?

FaceBook沒有在文章中描述實(shí)現(xiàn)原理。我們可以看看HDFS是怎么實(shí)現(xiàn)的。
數(shù)據(jù)平衡過程由于平衡算法的原因造成它是一個(gè)迭代的、周而復(fù)始的過程。每一次迭代的最終目的是讓高負(fù)載的機(jī)器能夠降低數(shù)據(jù)負(fù)載,所以數(shù)據(jù)平衡會(huì)最大程度上地使用網(wǎng)絡(luò)帶寬。下圖1數(shù)據(jù)平衡流程交互圖顯示了數(shù)據(jù)平衡服務(wù)內(nèi)部的交互情況,
包括NameNode和DataNode。

步驟分析如下:

數(shù)據(jù)平衡服務(wù)首先要求NameNode生成DataNode數(shù)據(jù)分布分析報(bào)告。選擇所有的DataNode機(jī)器后,要求NameNode匯總數(shù)據(jù)分布的具體情況。確定具體數(shù)據(jù)塊遷移路線圖,保證網(wǎng)絡(luò)內(nèi)最短路徑,并且確保原始數(shù)據(jù)塊被刪除。實(shí)際開始數(shù)據(jù)塊遷移任務(wù)。數(shù)據(jù)遷移任務(wù)完成后,通過NameNode可以刪除原始數(shù)據(jù)塊。NameNode在確保滿足數(shù)據(jù)塊最低副本條件下選擇一塊數(shù)據(jù)塊刪除。NameNode通知數(shù)據(jù)平衡服務(wù)任務(wù)全部完成。

HDFS數(shù)據(jù)在各個(gè)數(shù)據(jù)節(jié)點(diǎn)間可能保存的格式不一致。當(dāng)存放新的數(shù)據(jù)塊(一個(gè)文件包含多個(gè)數(shù)據(jù)塊)時(shí),NameNode在選擇數(shù)據(jù)節(jié)點(diǎn)作為其存儲(chǔ)地點(diǎn)前需要考慮以下幾點(diǎn)因素:

當(dāng)數(shù)據(jù)節(jié)點(diǎn)正在寫入一個(gè)數(shù)據(jù)塊時(shí),會(huì)自動(dòng)在本節(jié)點(diǎn)內(nèi)保存一個(gè)副本??绻?jié)點(diǎn)備份數(shù)據(jù)塊。相同節(jié)點(diǎn)內(nèi)的備份數(shù)據(jù)塊可以節(jié)約網(wǎng)絡(luò)消耗。HDFS數(shù)據(jù)均勻分布在整個(gè)集群的數(shù)據(jù)節(jié)點(diǎn)上。

FaceBook采用內(nèi)存+磁盤的方式存儲(chǔ)日志,HDD硬盤可以達(dá)到100-200MBps每秒的順序讀寫速度,隨機(jī)讀寫速度頂峰可以達(dá)到100-140MBps每秒。用來存儲(chǔ)日志的服務(wù)被稱為LogsDB,它是針對(duì)寫入性能進(jìn)行特殊優(yōu)化過的。LogsDB本身又是構(gòu)建于RocksDB之上的,RocksDB是基于LSM樹的有序Key-Value存儲(chǔ)層。RocksDB的每一個(gè)實(shí)例對(duì)應(yīng)LogsDB的分區(qū),當(dāng)寫入日志文件時(shí),會(huì)寫入到最新的分區(qū),也就是最近訪問過的RocksDB實(shí)例(以log id、LSN排序),然后以順序方式保存到磁盤(稱為SST文件)。這種方式確保了寫入的方式是順序方式,但是需要合并文件(當(dāng)達(dá)到LogsDB分區(qū)的最大文件數(shù)量時(shí))。

總結(jié)

就在我寫文章的時(shí)候,微博因?yàn)椤奥龟辖榻B女朋友”事件奔潰了,系統(tǒng)啟動(dòng)之后的數(shù)據(jù)同步、驗(yàn)證過程,日志的作用非常重要。目前LogDevice還沒有開源,但是從它的介紹來看,它應(yīng)該是結(jié)合了FaceBook內(nèi)部的多個(gè)開源項(xiàng)目的精髓,例如Cassandra,它的無中心化存儲(chǔ)、碎片化存儲(chǔ)(SSTable)、SSTable文件合并等等優(yōu)秀的特性,為確保日志文件的高速寫入、快速讀取提供技術(shù)支撐。FaceBook已經(jīng)明確今年年底會(huì)開源LogDevice,喜歡分布式實(shí)時(shí)處理、存儲(chǔ)系統(tǒng)的同學(xué)們,就等著它了。

極客網(wǎng)企業(yè)會(huì)員

免責(zé)聲明:本網(wǎng)站內(nèi)容主要來自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請(qǐng)進(jìn)一步核實(shí),并對(duì)任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對(duì)有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁或鏈接內(nèi)容可能涉嫌侵犯其知識(shí)產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書面權(quán)利通知或不實(shí)情況說明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開相關(guān)鏈接。

2017-10-25
LogDevice:來自Facebook的分布式日志數(shù)據(jù)存儲(chǔ)系統(tǒng)
作者:麥克周? 寫在前面 做過分布式系統(tǒng)的人都知道,想要在大規(guī)模集群下處理高并發(fā)事務(wù)時(shí)同時(shí)滿足CAP(一致性、可用性、分區(qū)容錯(cuò)),從理論上來說不可能,當(dāng)然聽

長按掃碼 閱讀全文