Facebook 在今年六月 SIGMOD 2011 上發(fā)表了一篇名為“Apache Hadoop Goes Realtime at Facebook”的會(huì)議論文 (pdf),介紹了 Facebook 為了打造一個(gè)實(shí)時(shí)的 HBase 系統(tǒng)使用到的獨(dú)門秘技。由于該論文提到的應(yīng)用場景與小弟負(fù)責(zé)的系統(tǒng)要解決的問題域有相似之處,因而抽時(shí)間仔細(xì)閱讀了這篇論文。下面便是結(jié)合論文的內(nèi)容,談一談我的一些看法和感想,如有謬誤,敬請指正。
這篇 10 頁的長文主要的內(nèi)容是 Facebook 在 Hadoop 系統(tǒng)上的工程實(shí)踐,這些工程實(shí)踐的目標(biāo)則是題目所點(diǎn)出的——實(shí)時(shí)。雖然缺乏 Hadoop 系統(tǒng)的開發(fā)或使用經(jīng)驗(yàn),但是我覺得并沒有妨礙我對這篇論文的理解。在我的腦子里,HDFS 就是 GFS,HBase 就是 BigTable。它們實(shí)現(xiàn)上可能有差異之處,但主要的思想應(yīng)該是相通的。如果熟悉 GFS 和 BigTable 那兩篇文章,這篇文章就可以視為 GFS 和 BigTable “進(jìn)階”。
1. 應(yīng)用場景和需求
文章的最初是一些背景介紹,主要給出了三類應(yīng)用場景:Facebook Messaging、Facebook Insight 和 Facebook Metrics System(ODS)。Messaging 就是 Facebook 的新型消息服務(wù),Insight 是提供給開發(fā)者和網(wǎng)站主的數(shù)據(jù)分析工具,ODS 則是 Facebook 內(nèi)部的軟硬件狀態(tài)統(tǒng)計(jì)系統(tǒng)。這三個(gè)應(yīng)用場景都有各自的特色,但簡單地來說,面臨的問題是同樣的:單機(jī)或者拆分的關(guān)系型數(shù)據(jù)庫無法滿足需求。
基于應(yīng)用場景的數(shù)據(jù)特征,F(xiàn)acebook 抽象出了幾個(gè)對存儲(chǔ)系統(tǒng)的需求。由于描述起來有些復(fù)雜,例如 Efficient and low-latency strong consistency semantics within a data center,這些需求就不一一列舉了。相比需求,更讓人感興趣的是它的那些“非需求”,總共有三條:
- 容忍單數(shù)據(jù)中心內(nèi)部的網(wǎng)絡(luò)分化,F(xiàn)acebook 認(rèn)為這個(gè)問題應(yīng)該從網(wǎng)絡(luò)硬件層面(做冗余設(shè)計(jì))而不是軟件層面去解決;
- 單個(gè)數(shù)據(jù)中心宕機(jī)不影響服務(wù),F(xiàn)acebook 認(rèn)為這種災(zāi)難很難發(fā)生,因而愿意接受這種風(fēng)險(xiǎn);
- 跨數(shù)據(jù)中心的數(shù)據(jù)熱備服務(wù)能力,F(xiàn)acebook 假設(shè)用戶數(shù)據(jù)是分配到固定的數(shù)據(jù)中心的,可能帶來的響應(yīng)延遲問題應(yīng)該通過緩存來解決。
從這些“非需求”上可以看出,F(xiàn)acebook 考慮的是更實(shí)際的情況,而不是一個(gè)理想中的分布式系統(tǒng),在這點(diǎn)上有一定的借鑒意義。
根據(jù)以上的需求和非需求,F(xiàn)acebook 自然而然地給出選擇 Apache Hadoop 這套系統(tǒng)的理由,其中有社區(qū)的成熟度、Hadoop 在一致性、擴(kuò)展性、可用性、故障容忍、讀寫效率等等的各項(xiàng)優(yōu)點(diǎn),這些方面的優(yōu)點(diǎn)也是有目共睹的。
2. 打造實(shí)時(shí)的 HDFS
HDFS 本身設(shè)計(jì)來支持離線 MapReduce 計(jì)算的分布式文件系統(tǒng),雖然在擴(kuò)展性和吞吐上有很好的表現(xiàn),但在實(shí)時(shí)性方面表現(xiàn)并不好。如果想讓基于 HDFS 的 HBase 有更好的性能,HDFS 層的優(yōu)化是不可避免的。為了把 HDFS 打造成一個(gè)通用的低時(shí)延文件系統(tǒng),F(xiàn)acebook 主要做了以下一些優(yōu)化。
2.1 實(shí)現(xiàn) NameNode 的高可用——AvatarNode
HDFS 的 NameNode 是系統(tǒng)單點(diǎn),就意味著 NameNode 掛掉會(huì)導(dǎo)致系統(tǒng)的不可用。NameNode 重啟時(shí)加載內(nèi)存快照、應(yīng)用log和收集 DataNode 的數(shù)據(jù)塊信息報(bào)告大概需要 45 分鐘。即便使用了 BackupNode,仍然需要收集數(shù)據(jù)塊信息報(bào)告,切換的時(shí)間仍然可能大于 20 分鐘。但有實(shí)時(shí)性需求的系統(tǒng)一般都會(huì)要求系統(tǒng) 24x7 的可用性,因而 Facebook 對單點(diǎn)的 NameNode 進(jìn)行了改進(jìn),實(shí)現(xiàn)了 NameNode 的雙節(jié)點(diǎn)熱備,稱為 AvatarNode,如下圖所示:
簡單地來說,備份 AvatarNode 通過 NFS 讀取并回放主 AvatarNode 的事務(wù)日志來保持?jǐn)?shù)據(jù)的同步,并同時(shí)接收 DataNode 的數(shù)據(jù)塊信息報(bào)告,這保證了主備 AvatarNode 的數(shù)據(jù)差距盡可能地小,使得備份 AvatarNode 能夠很快地切換為主節(jié)點(diǎn)的角色。主備 AvatarNode 的角色是注冊到 ZooKeeper 中的,DataNode 可以根據(jù) ZooKeeper 中信息判斷需要服從哪個(gè) AvatarNode 節(jié)點(diǎn)的指令。
為了實(shí)現(xiàn)熱備 AvatarNode 的數(shù)據(jù)同步和易用性,F(xiàn)acebook 還改進(jìn)了 NameNode 事務(wù)日志,并部署了 DAFS (Distributed Avatar File System) 屏蔽了 AvatarNode 的故障切換,使得這些改變對客戶端透明。文中并沒有提到 AvatarNode 的切換是手工還是自動(dòng)進(jìn)行的,但是考慮到 ZooKeeper 的 lease 機(jī)制,自動(dòng)切換應(yīng)該不難實(shí)現(xiàn)。
2.2 Hadoop RPC 兼容性和數(shù)據(jù)塊可用性
在之前的系統(tǒng)需求中,有提到一點(diǎn)是 Fault Isolation,并且 Facebook 的 Hadoop 系統(tǒng)是在單機(jī)房部署的,因而同一個(gè)服務(wù)必然會(huì)使用多套 Hadoop 系統(tǒng)。為了系統(tǒng)升級獨(dú)立方便,使客戶端兼容不同版本的 Hadoop RPC 是自然而然的事情。
HDFS 在分配副本數(shù)據(jù)塊位置時(shí),雖然會(huì)考慮到機(jī)架位,但整體來說仍然是相當(dāng)隨機(jī)的。其實(shí)我以前也曾經(jīng)與同事討論過類似的問題,到底是選擇隨機(jī)分配副本位置,還是使用一定的組策略去分配。隨機(jī)分配的好處是簡單均衡,壞處是一旦發(fā)生多臺宕機(jī),由于副本隨機(jī)分布,導(dǎo)致某塊數(shù)據(jù)副本全部丟失概率很大;用一定的組策略去分配的好處是多臺宕機(jī)如果不發(fā)生在同一組里,不會(huì)丟數(shù)據(jù),但是一旦多臺宕機(jī)發(fā)生在同一組,會(huì)丟很多數(shù)據(jù)。看來 Facebook 是選用了組策略分配的方法,認(rèn)為多臺宕機(jī)發(fā)生在同一組的概率不大。
但這樣做是否正確,我是有疑問的。同一個(gè)機(jī)架或相鄰機(jī)架上的服務(wù)器一般上架時(shí)間、硬件型號等都相同,那么同時(shí)發(fā)生故障的事件不是完全獨(dú)立的,其概率是要大于理想故障分布情況下概率的。我想這也是為什么 Facebook 最終方案中一組機(jī)器是 (2, 5),2 個(gè)機(jī)架,5 臺服務(wù)器。這兩個(gè)機(jī)架的選擇,如果很謹(jǐn)慎的話,能夠盡量避免我說的這種情況。不過,凡事還得看執(zhí)行力,如果不了解部署情況去選擇機(jī)架的話,不一定能夠達(dá)到預(yù)期效果。
2.3 實(shí)時(shí)負(fù)載的性能優(yōu)化
除了上面的改動(dòng)之外,F(xiàn)acebook 還對客戶端的 RPC 過程進(jìn)行了優(yōu)化。為 RPC 添加超時(shí)機(jī)制,加快文件 lease 的撤銷速度(由于對 HDFS 文件操作不了解,我沒明白為什么要加快 lease 撤銷)。
此外,還提到了最重要的一點(diǎn):局部性!Facebook 增加了一個(gè)檢查文件塊是否在本機(jī)的功能,如果在本機(jī)就直接讀取。不知道它具體實(shí)現(xiàn)方式是怎樣的,但我覺得這個(gè)做法其實(shí)是“很黃很暴力”的,不知道會(huì)不會(huì)破壞數(shù)據(jù)一致性。
2.4 HDFS sync 優(yōu)化和并發(fā)讀
為了提高寫性能,F(xiàn)acebook 允許不等待 sync 結(jié)束就繼續(xù)寫,這一點(diǎn)看起來也很暴力,不知道會(huì)不會(huì)影響數(shù)據(jù)正確性。
為了能夠讀到最新數(shù)據(jù),F(xiàn)acebook 允許客戶端讀一個(gè)還未寫完的數(shù)據(jù)文件。如果讀到正在寫入的最后一個(gè)塊,就重新計(jì)算 checksum。
3. 打造實(shí)時(shí)生產(chǎn)壞境的 HBase
3.1 行級別原子性和一致性
雖然 HBase 已經(jīng)保證了行級別的原子性,但節(jié)點(diǎn)宕機(jī)可能導(dǎo)致最后一條更新日志不完整。Facebook 不夠滿意,引入了 WALEdit,一個(gè)日志事務(wù)概念來保證每條更新日志的完整性。
一致性方面,看來 HBase 能夠滿足需求。不過對于 3 個(gè)副本同時(shí)校驗(yàn)失敗導(dǎo)致數(shù)據(jù)塊不可用的情況,F(xiàn)acebook 增加了事后分析的機(jī)制,而不是簡單丟棄。
3.2 可用性
為了提高 HBase 的可用性,F(xiàn)acebook 對其進(jìn)行了完善的測試,并解決了以下幾個(gè)問題:
- 重寫 HBase Master,將 ragion 分配信息存儲(chǔ)到 ZooKeeper 中以保證宕機(jī)切換正確完成。
- 使得 compaction 可以中斷以加速 RegionServer 的正常退出速度,并實(shí)現(xiàn) rolling restarts(就是逐臺升級),降低程序升級對服務(wù)的影響。
- 將宕機(jī) RegionServer 的日志拆分功能從 Master 中拆離,由多個(gè) RegionServer 進(jìn)行拆分,以提高 RegionServer 故障恢復(fù)效率。
這幾個(gè)問題的解決倒是有通用的用途,我想不久以后很有可能會(huì)合并到 Hadoop 的代碼中。
3.3 性能優(yōu)化
性能優(yōu)化主要從兩點(diǎn)進(jìn)行,一個(gè)是 compaction 性能,另一個(gè)是讀性能。
讀過 BigTable 論文的應(yīng)該對其 memtable 和 compaction 的特性比較熟悉。這里主要討論了讓 minor compaction 也刪除數(shù)據(jù)的好處,以及如何做 major compaction 能夠提高合并的性能。
在數(shù)據(jù)讀性能方面,文章里主要討論了減少 IO 操作的方法,其中包括 bloom filter 和特定類型 meta 信息(時(shí)間戳)的使用。還有很重要的一點(diǎn),在部署上保持 RegionServer 和物理文件的局部性!
文章后面還給出了 Facebook 在部署和運(yùn)維方面的一些經(jīng)驗(yàn),其中有一些有趣的點(diǎn),我后續(xù)可能會(huì)寫篇文章專門討論,這里就不詳細(xì)說明了。
4. 總結(jié)
以前我們也曾經(jīng)討論過如何在分布式文件系統(tǒng)的基礎(chǔ)上搭建一套實(shí)時(shí)數(shù)據(jù)分析系統(tǒng),當(dāng)時(shí)認(rèn)為如果有成熟的 GFS 可用的話,這個(gè)工作會(huì)比較簡單?,F(xiàn)在讀到 Facebook 的這篇文章,才發(fā)現(xiàn)當(dāng)初想法的幼稚。僅僅從這篇文章中的技術(shù)點(diǎn)體現(xiàn)出的工作量來看,文中說這個(gè)系統(tǒng)是多年持續(xù)工作的結(jié)晶是令人信服的。當(dāng)然,這也意味著想復(fù)制一套這樣的系統(tǒng)并不是件輕松容易的事。
從系統(tǒng)設(shè)計(jì)的成果來看,這個(gè)系統(tǒng)應(yīng)該能達(dá)到文章開頭制定的需求目標(biāo),并也能夠滿足大部分應(yīng)用場景的需要。不過有一點(diǎn),我存在疑問,即是為 Insights 提供的 Realtime Analytics 功能。Realtime 沒問題,但使用 HBase, Analytics 究竟能支持多好呢?可能還需要再去了解 HBase 的功能才能有答案。
從這個(gè)系統(tǒng)的很多細(xì)節(jié)可以發(fā)現(xiàn),有不少折中和 trick。我想這就是現(xiàn)實(shí)世界,凡事很難做到盡善盡美,工程也一樣。在設(shè)計(jì)系統(tǒng)時(shí)追求完美沒有錯(cuò),但是需要考慮代價(jià)和可行性,不要忘記滿足需求才是最重要的目標(biāo)。除此之外,也不妨再列出一些“非需求”,排除這些限制可能會(huì)降低不少的系統(tǒng)復(fù)雜度。