Apache Hadoop Goes Realtime at Facebook(中文,Hadoop在臉譜達成實時應用)

作者:Dhruba BOrthakur & Joydeep Sen Sarma etc. Facebook Inc 2011-6

原文:http://wenku.baidu.com/view/5b1f48ef0975f46527d3e18b.html

譯者:phylips@bmy 2011-9-11

出處:http://duanple.blog.163.com/blog/static/7097176720118121573597/

摘要

Facebook最近部署了Facebook Messages,這是它的首個構建於Apache Hadoop平臺上的user-facing應用。使用構建於Hadoop之上的類數據庫層Apach HBase來對每天數十億的消息信息進行處理支持。這篇論文描述了Facebook在衆多系統中(比如Apache Cassandra,Voldemort)最終選擇了Hadoop和HBase的原因,並討論了應用程序在一致性、可用性、分區容忍性、數據模型及可擴展性上的需求。我們還會探討一下爲了讓Hadoop成爲一個更有效的實時性系統所做的那些改進,在配置系統過程中所做的那些權衡,以及這種基於Hadoop的解決方案與Facebook和很多其他互聯網公司在很多應用程序中採用的那種分片(sharded)MySQL數據庫模式相比所具有的優勢。我們還會討論各種設計選擇的背後動機,我們在日常工作中面臨的挑戰,一些未來的還在開發中的功能和改進。我們提供的這些關於部署中的各種觀點可以爲那些正在考慮使用基於Hadoop的解決方案取代傳統分片RDBMS部署的公司,提供一種參考性的模型。

 

關鍵詞

數據 可擴展性 資源共享 分佈式文件系統 Hadoop Hive HBase Facebook Scribe 日誌聚合 分佈式系統


1.導引

Apache Hadoop是一個頂級的Apache開源項目,它包含一個源於Google GFS和MapReduce的分佈式文件系統和MapReduce的開源實現。整個Hadoop生態系統還包括像Apache HBase(源於Google BigTable),Apache Hive(一個構建在Hadoop之上的數據倉庫)及Apache Zookeeper(一個用於分佈式系統的協商服務)這樣的一些項目。

 

在Facebook,Hadoop早已與Hive結合在一塊,進行海量數據集的存儲和分析。大部分的分析工作都是離線的批處理式job,側重點在於最大化吞吐量和效率。典型的工作負載就是從磁盤上順序讀寫大量數據。如此一來,對於通過提供對HDFS的低延遲訪問而使得Hadoop能夠更好的支持隨機訪問類型的負載缺乏重視。事實上,目前我們是通過將一堆的MySQL數據庫集羣和使用memcached構建的緩衝層結合起來解決這些問題。很多情況下,來自Hadoop的結果會被上傳到MySQL或者是memcached爲web層提供服務。

 

最近,那些需要高度寫吞吐率和廉價彈性存儲的新一代應用程序在Facebook逐漸興起,這些應用程序同時還要求低延遲以及高效的硬盤順序和隨機讀性能。衆所周知MySQL存儲引擎具有非常好的隨機讀性能,但是隻能提供非常低的隨機寫吞吐率。同時很難在保證良好的負載平衡及高的持續運行時間的情況下,對MySQL進行快速的垂直擴展{!scale up和scale out,水平擴展和垂直擴展,Scale Out(水平擴展):根據需求增加服務器,依靠多部服務器協同運算,借負載平衡及容錯等功能來提高運算能力及可靠度。Scale Up(垂直擴展):升級服務器以增加處理器等運算資源進行升級以獲得對應用性能的要求。}。對於MySQL集羣的管理需要相對較高的管理開銷,同時它們通常需要使用更昂貴的硬件。基於對HDFS的可靠性和可擴展性的高度自信,我們開始探索讓這樣的應用程序採用Hadoop和HBase。

 

基本上我們可以將這些應用程序劃分爲兩類。第一種應用程序集需要實時的併發性,對存儲在HDFS上的非常大的實時性數據流進行順序讀訪問。比如Scribe(由Facebook創建並廣泛使用的一個開源的分佈式日誌聚合服務)就是一個生成和存儲這種數據的實例系統。之前,由Scribe生成的數據會被存儲在昂貴而難以管理的NFS服務器上。屬於這種類型的應用還有Realtime Analytics和MySQl backups。我們已對HDFS進行了改進,使得它成爲一個高性能低延遲的文件系統,通過它已能夠減少這種昂貴的文件服務器的使用。

 

第二種非MapReduce Hadoop應用需要支持快速的隨機查找,動態的爲一個快速增長數據集建立索引。一個主要的例子就是Facebook Messages。Facebook Messages提供給每個用戶一個facebook.com的電子郵件地址,負責所有的電子郵件、SMS以及兩個人的或者是一組用戶的聊天信息的展示,需要對用戶信息的來源進行強力地控制管理,是Social Inbox的基礎。此外,這個新的應用會被超過5億的用戶在茶餘飯後使用,需要能夠擴展到數PB的數據,同時具有嚴格的正常運行時間需求。我們決定爲這個項目採用HBase。HBase實際上依賴於HDFS提供可擴展性、容錯性存儲,依賴於Zookeeper提供分佈式一致性。

 

在下面的章節中,我們會對這些新型應用中的某些進行更詳細的介紹,並說明我們決定採用Hadoop和HBase作爲這些項目的通用基礎技術的原因。我們會描述爲了可以適應Facebook的工作負載、運營考慮以及達到在產品系統中的最佳實踐,針對HDFS和HBase進行的具體改進。


2.工作負載類型

在做出是否採用一個特殊的軟件系統以及是否從當前的基於MySQL架構上進行遷移的決定之前,我們仔細考察了一些具體應用,對於這應用來說現有解決方案可能會成爲一個問題。這些應用可能會由於其工作負載具有非常高的寫吞吐量、大規模的數據集、不可預測的增長率、或者某些在一個分片(sharded)RDBMS環境中很難做到或者次優的問題,而導致難以擴展。


2.1Facebook Messaging

最新版的Facebook Messaging整合了現有的e-mail,chat和SMS服務。除了保留了所有這些信息外,新的主題模型還要求爲所有的參與者保存信息。作爲應用服務器需求的一部分,每個用戶將會被綁定到一個數據中心。


2.1.1高的寫吞吐量

根據現有的數百萬消息產生率及每天數十億的即時消息量,每天需要導入的數據量是非常巨大的,同時還在持續的增長。各種非規範化的需求還會增加系統的實際寫入量,因爲每條消息實際中可能會被寫入多次。


2.1.2Large Tables

作爲產品需求的一部分,消息不能被刪除除非用戶顯示的進行了該操作,這樣每個mailbox將會無限增長。與大多數的通訊應用類似,只有那些最近的消息可能會被讀取有限的幾次,之後就很少會被讀取。也就是說,絕大多數的內容都不會再從數據庫中讀出,但是它們必須是時刻可用的,同時還需要低延遲,因此很難直接進行歸檔。

 

存儲用戶的所有消息意味着我們需要一個包含了日益增長的主題列表和消息內容的按用戶進行索引的數據庫模式。對於隨機寫負載類型來說,伴隨着表中行數的增加,MySQl這類系統的寫性能會顯著的降低。數目衆多的新消息也意味着一個沉重的寫操作負載,在這種類型的系統中這些寫操作會被轉換爲大量的隨機IO操作。


2.1.3數據遷移

新的Messaging產品最具挑戰性的方面在於新的數據模型上。這意味着所有現有的消息需要被重新擺弄一遍,以適應新的主題模型,然後進行遷移。能夠進行大規模scan、隨機訪問以及快速的大批量導入將會有助於減少將用戶遷移到新系統上的時間開銷。


2.2Facebook Insights

Facebook Insights提供給開發者和網站站長訪問具有社會化插件、Facebook Pages、Facebook Ads的那些網站的Facebook activity相關的實時分析結果。

 

通過使用不具名數據,Facebook記錄那些諸如廣告收視次數、點擊率、網站訪問量這樣的一些數據。這些分析可以幫助人們瞭解其他人是如何與網站內容進行交互,這樣他們就可以對他們的服務進行優化。

域名和URL分析以前是通過我們的Hadoop和Hive以一種離線處理的方式週期性的生成。但是,這產生了比較糟糕的用戶體驗,因爲結果可能需要花幾個小時等數據處理完成時纔可用。


2.2.1實時性Analytics

Insights團隊希望他們的用戶可以在幾秒內而不是之前的幾小時就能看到統計結果。這除了需要一個進行處理、聚合、事件保存的系統外,還需要爲用戶的請求提供一個大規模的,異步隊列系統。這些系統都需要是容錯的,並能夠支持每秒上百萬的事件。


2.2.2High Throughput Increments

爲了支持現有的Insights功能,時間和基於人口特徵的聚合是必要的。然而,這些聚合操作必須要保證是最新狀態,因此它們的處理必須是不落地的(on the fly),一次一個事件,通過數字型計數器實現。在具有數百萬的單一聚合器及數十億的事件的情況下,意味着大量的計數器都會具有大量的針對它們的操作。


2.3Facebook Metrics System(ODS)

在Facebook,所有的硬件和軟件會把統計信息傳給一個稱爲ODS(Operations Data Store)的度量信息(metrics)收集系統。比如,我們可能會收集在給定的某個服務器或者一系列服務器上的CPU使用量,或者我們可能想追蹤針對某個HBase集羣的寫操作數。對於每個或者一組節點,我們會追蹤成百上千個不同的metrics,同時工程師可能希望以不同的粒度在時間軸上將它們繪出。該應用對於寫吞吐量有很高的需求,現有的基於MySQL的系統在數據的resharding和進行表的掃描時存在很大的問題,時間會不斷攀升。


2.3.1Automatic Sharding

大量的被索引的基於時間序列的寫操作,以及不可預測的增長率使得一個分片的MySQL配置很難滿足這些情況的處理。比如,一個給定的產品可能在很長的時間內只收集10個metrics,但是伴隨着大規模的產品推出和發佈,相同的產品可能會產生數千個metrics。對於現有的系統來說,一個MySQL服務器的負載可能會突然超出它所能提供的處理水平,這就迫使該產品的團隊手動的把數據從這個服務器進行re-shard,以遷移到多個服務器上。


2.3.2近期數據的快速讀取及表的掃描

對於metrics系統的絕大部分的讀取都是針對那些最近的原始數據,但是所有的歷史性數據也必須是可用的。最近寫入的數據必須很快就是可見的,此外爲了執行基於時間的彙總統計,整個數據集合也需要被週期性地掃描。


3.Why Hadoop And HBase

上面所描述的工作負載類型對存儲系統的需求可以概括如下(排名不分先後):

l  彈性:我們需要能夠在最小化開銷及不停機的情況下,增加存儲系統的容量。某些情況下我們希望可以快速的增加容量,然後系統可以自動的進行負載平衡同時能夠利用起新的硬件。

l  高的寫吞吐率:大部分應用會存儲(可能還會進行索引)大量的數據,同時需要達到很高的寫吞吐率。

l  在單個數據中心內的高效的低延遲的強一致性語義:一些重要的應用比如Messages需要在單數據中心內的強一致性。這個需求是直接由用戶的期望體驗決定的。比如,顯示在用戶主頁上的未讀消息個數,以及顯示在收信框頁面的消息在用戶之間應該是一致的。現實來看,實現一個全局的分佈式強一致性系統是很難的,但是一個至少能在單個數據中心內部提供這種強一致性的系統已經可以提供一種較好的用戶體驗。我們也意識到(不像其他的Facebook應用)Messages可以很簡單的進行聯合這就可以讓一個用戶限制在單個數據中心的服務的範圍,這就使得單數據中心的強一致性成爲Messages項目的關鍵需求。類似地,其他的項目比如實時日誌聚合,也可以整個地部署在一個數據中心內,如果系統提供了強一致性保證就更容易進行編程。

l  高效的磁盤隨機讀:儘管應用級cache被廣泛使用(要麼通過內嵌的要麼通過memcached),在Facebook的應用場景中,會存在大量無法命中cache的操作而需要訪問後端的存儲系統。MySQL可以高效的執行隨機讀操作,任何的新系統必須不能比它差。

l  高可用性及災難恢復:我們的服務需要爲用戶提供一個高的正常運行時間,即使是面臨一些計劃或非計劃的事件時(有計劃的比如軟件升級,硬件/容量擴容,非計劃的比如硬件錯誤)。我們還需要能夠容忍某個數據中心的失敗並最小化數據丟失,同時能夠在合理的時間窗口內通過另一個數據中心提供數據服務。

l  故障隔離性:長期運營MySQL數據庫的經驗表明,故障隔離性是至關重要的。各個數據庫肯定會有down掉的情況,但是在這種情況發生時應該隻影響到很少的一部分用戶。類似地,在我們的Hadoop數據倉庫使用中,單個的磁盤故障只會影響到一少部分的數據,同時系統可以很快地從這種故障中恢復。

l  原子性的讀-改-寫原語:原子性的increments和compare-and-swap API在構建無鎖(lockless)並行程序中非常有用,而且也是底層存儲系統必須要具備的。

l  Range Scans:一些應用需要能夠高效地檢索在特殊邊界中的行集合。比如,針對給定用戶的最新的100條消息,或者是給定的某廣告客戶在最近的24小時的每小時廣告投放次數。

指出那些non-requirements也是很有必要的:

n  單數據中心內的網絡分區容忍性:不同的系統組件通常具有一些固有的中心化。比如,所有的MySQL服務器會被放置在一些機櫃之內,數據中心內的網絡分區(network partition)可能會導致其中的大部分都喪失服務能力。因此我們是通過在硬件級別上通過高度冗餘的網絡設計儘可能地降低這種事件發生的可能性。

n  在單個數據中心故障發生時的零downtime:根據我們的經驗,儘管不是不可能的,但是這樣的故障很少發生。在一個非理想的現實世界中,系統設計需要做出可以接受的各種折中選擇,這個就是我們在這種事件很少發生的給定前提下做出的一個折中。

n  跨數據中心的active-active服務能力{!雙工熱備,即兩個數據中心提供對等的數據服務能力,一個掛了還有另一個可以提供服務}:如前面提到的那樣,我們可以方便地對跨越多個數據中心的用戶數據進行組合(基於用戶的位置)。通過使用一個靠近用戶的應用級cache可以掩蓋其中的延遲(當用戶和data locality不匹配時會產生比較大的延遲)。

 

某些看起來不是那麼明顯的因素也會起到作用。我們會更傾向於那些對於Facebook來說已經具有產品經驗或者內部開發經驗的系統。{!學習一個新的系統是需要成本的,如果這些系統已經在Facebook使用或研究過,那麼當它出了問題時就能更好更快的解決它}。在考慮開源項目時,社區力量也是一個重要的考慮因素。在構建和維護這些系統的工程投入給定的情況下,選擇一個更通用的解決方案會更有意義(而不是爲不同的工作負載重新改變架構和代碼實現)。

 

經過大量的研究和實驗之後,我們選擇採用Hadoop和HBase作爲我們的新一代應用程序的基礎存儲技術。這個決定是基於當前針對HBase的評估以及我們相信可以通過自己內部的開發解決它當前缺乏的features。HBase已經提供了一個高一致性的,高寫吞吐率的key-value存儲。HDFS NameNode存在一個突出的單點失敗問題,但是我們相信我們的HDFS團隊可以在合理的時間窗口內構建一個高可用的NameNode,這對於我們的數據倉庫應用也是有益的。好的磁盤讀效率看起來也很容易達到(爲HBase的LSM Tree實現添加Bloom filter,優化local的DataNode讀取,緩存NameNode元數據)。基於我們在Hive/Hadoop數據倉庫上的經驗,我們認爲HDFS是對磁盤子系統上的故障進行容錯和隔離的關鍵。在大規模的HBase/HDFS集羣中出現的失敗與我們的故障隔離目標背道而馳,但是它可以通過將數據存儲在較小規模的集羣上得到明顯的緩解。各種replication項目,包括我們自己及整個HBase社區內部,看起來這將會爲災難恢復提供可行的方案。

 

HBase具有高度的擴展性,除了隨機和流式讀操作還可以支持快速的隨機寫。它也提供了一個行級別的原子性保證,但是沒有原生的跨行事務支持。從數據模型角度上來看,列式存儲在數據存儲上提供了高度的靈活性,wide row{!當在傳統的關係數據庫中設計table時,典型用“entities(實體)”處理,或一系列描述性的屬性。對於row自身的長度無需考慮過多,因爲一旦定義了你的table有哪些列組成,row的長度就是確定的了。而一個wide row意味着一條記錄有很多columns(甚至可以是數以百萬的)}使得可以在一個table裏創建數10億的indexed value。HBase特別適合於那些寫密集型的,需要維護大量數據的,大量索引的工作負載,同時保持了快速進行水平擴展的靈活性。


4.實時性HDFS

HDFS是一個最初設計用於支持離線MapReduce應用的文件系統,作爲一種批處理系統,在這種情況下,可擴展性和streaming處理性能纔是最重要的。使用HDFS有如下優點:線性的可擴展能力及容錯性,可以爲公司節省大量花費。那些新式的、更實時性及在線的HDFS應用提出了新的需求,目前我們使用HDFS作爲一個通用的低延遲文件系統。在本節內,我們會描述下爲支持這些新型的應用我們對HDFS進行的核心改動。


4.1高可用性-AvatarNode

HDFS的設計中有一箇中央master--the NameNode。當master down掉的時候,HDFS集羣必須等到NameNode恢復後纔可用。這是一個明顯的單點失敗,也是爲什麼人們很難將它部署在一個需要7×24小時運行的應用中的原因之一。在我們的使用過程裏,發現軟件的升級是我們的HDFS集羣停機的首要原因。因爲硬件並非是完全的不可靠,而軟件在部署到生產集羣上之前都進行了嚴格地測試,在我們管理HDFS集羣的四年時間裏,只碰到過一次例外,那次是因爲事務日誌被存儲到一個已損壞的文件系統中導致了NameNode的crash。


4.1.1熱備份(Hot Standby)-AvatarNode

啓動時,HDFS NameNode會從一個叫做fsimage的文件中讀取文件系統元數據。元數據包含了HDFS中的每個文件和目錄的名稱和元數據。然而,NameNode並沒有持久化存儲每個block的位置信息。因此,一個NameNode的冷啓動由兩個主要過程組成:首先,讀取文件系統image,applying事務日誌,將新的文件系統image存回磁盤;其次,處理來自DataNode的block報告以恢復集羣中的block的位置信息。我們最大的HDFS集羣大概有150 million個文件,我們觀察到這兩個階段大概花了相同的時間。總的算下來,一次冷啓動花了大概45分鐘。

 

Apache HDFS中提供的BackupNode可以避免在故障恢復的時候從磁盤中讀取fsimage,但是它仍然需要從所有的DataNode那收集block報告。因此BackupNode解決方案的故障恢復時間仍可能會高達20分鐘。我們的目標是在數秒內進行故障恢復;因此,BackupNode解決方案無法滿足我們對於快速的故障恢復的需求。另一個問題是,NameNode在每個事務發生時都需要同步地更新BackupNode,因此整個系統的可靠性甚至低於單個NameNode時的可靠性。於是,HDFS AvatarNode誕生了。

 

Apache Hadoop Goes Realtime at Facebook(譯) - 星星 - 銀河裏的星星 

{!Avatar,這裏的Avatar應該取自2009年在美國上映的影片<<Avatar>>(阿凡達)。Avatar本意是化身,影片中的傑克化身爲納美人,穿行於美麗的潘多拉星球,他具有人類與納美人兩種身份,但是同一時刻只有一個是active的。下面的AvatarNodes,其中一個Node便可以看成是另一個的化身,同時同一時刻只有一個是active的,與電影相比的確有些相通的地方。}

 

一個HDFS集羣有兩個AvatarNode:Active AvatarNode與Standby AvatarNode。它們形成了一個主從熱備組合。一個AvatarNode是對一個普通的NameNode的包裝。Facebook所有的HDFS集羣都是採用NFS來存儲一個文件系統image的拷貝以及一個事務日誌的拷貝。那個Active的 AvatarNode會將它的事務寫入到保存在NFS文件系統上的事務日誌中。與此同時,Standby 的AvatarNode會打開同一個事務日誌文件從NFS文件系統上開始讀取,同時開始將事務應用到自己的namespace中,來保證它的namespace儘可能地接近於primary。Standby 的AvatarNode也負責primary的check-pointing,以及創建新的文件系統image,這樣就不再存在一個獨立的SecondaryNameNode。{?SecondaryNameNode又是什麼呢?SecondaryNameNode實際上是在hadoop-0.21.0之前纔有的,到了0.21.0後SecondaryNameNode已被CheckpointNode和BackupNode取代。首先來看SecondaryNameNode存在的原因,NameNode在啓動時會讀取fsimage恢復內存狀態然後重放修改日誌文件中記錄的修改,之後再將新的內存狀態寫入到fsimage中,併產生一個新的空的修改日誌。由於NameNode只會在啓動時纔會對fsimage和修改日誌進行merge,這樣運行很長時間後,修改日誌會變得很大,這樣再NameNode下次重啓時將會花費很長時間進行merge。SecondaryNameNode的目的就是通過週期性的merge,使得修改日誌可以保持在一個較小的規模上。更具體細節可以參見Hadoop的官方文檔中的說明。Standby 是如何處理primary的check-pointing的?Standby實際上就可以充當SecondaryNameNode的角色,進行check-pointing} 

DataNode與Active AvatarNode和Standby AvatarNode都會進行通信,而不是隻跟單個NameNode通信。這意味着Standby AvatarNode也具有最新的關於block的位置信息,這樣在一分鐘內就可以順利地成爲Active的。Avatar DataNode會向這兩個AvatarNodes發送心跳,塊報告,以及接收到的block。AvatarDataNode會與Zookeeper進行交互,這樣他們就能知道目前哪個AvatarNode是primary的,同時它們只處理那些來自primary的AvatarNode的replication/deletion命令。來自Standby AvatarNode的replication/deletion命令將會被忽略。


4.1.2針對HDFS 事務日誌機制的改進

HDFS只有在文件關閉或者調用sync/flush時纔會將新分配的block-ids記錄到事務日誌中。由於我們想讓故障恢復儘可能地透明,那Standby AvatarNode就需要在故障發生時能夠知道所有的block分配,因此我們在每次塊分配時都向事務日誌中寫入一個新的事務。這就允許一個客戶端可以向它在故障恢復之前正在寫的那個文件繼續進行寫入。

 

在Standby AvatarNode從Active AvatarNode正在寫入的那個事務日誌中讀取事務時,存在只讀取到事務的一部分內容的可能性。爲了解決這個問題,我們需要修改日誌格式使它具有一個事務長度,事務id以及寫入到文件中的每個事務的校驗和。


4.1.3透明化的故障恢復:DAFS

我們開發了分佈式的Avatar文件系統(DAFS),一個提供給客戶端使之可以透明地跨越故障恢復事件訪問HDFS的上層文件系統。DAFS與Zookeeper進行協作。Zookeeper持有一個包含了給定集羣的關於Primary的AvatarNode的物理地址的zNode。當客戶端嘗試連接HDFS集羣(比如 dfs.cluster.com)時,DAFS會查看Zookeeper中持有實際Primary AvatarNode(dfs-0. cluster.com)的物理地址的zNode,並將所有的後續調用指向該Primary AvatarNode。當一個調用碰到一個網絡錯誤時,DAFS會檢查Zookeeper看primary是否發生了改變。假設現在發生了一個故障恢復事件,那麼zNode現在應該包含新的Primary AvatarNode的物理地址。DAFS會向這個新的Primary節點重試當前調用。我們沒有使用Zookeeper訂閱模型,因爲它會佔用Zookeeper服務器上更多的資源。如果一個故障恢復正在進行,那麼DAFS會自動阻塞直到故障恢復完成。這樣,一個故障恢復事件對於那些訪問HDFS數據的應用來說就是完全透明的。


4.2Hadoop RPC兼容性

從一開始,就很清楚我們會爲我們的Message應用運行多個Hadoop集羣。我們需要那種能夠在不同的時間點在不同的集羣上部署新軟件的能力。這就需要我們改進Hadoop Client,使得它們能夠同運行了不同版本的Hadoop軟件的Hadoop服務器進行交互。同一個集羣內部的不同服務器運行的是相同版本的軟件。我們增強了Hadoop RPC軟件來自動確定運行在它所通信的服務器上的軟件版本,然後在與服務器會話時選擇合適的協議。


4.3塊可用性:Placement策略

默認的HDFS塊放置策略,雖然是機櫃感知的,但限制仍然是最小化的。對於一個非local的放置決定是隨機的,它可以被放置在任意的機櫃上,以及機櫃內的任意節點上。爲了降低在多個節點同時出錯時的數據丟失概率,我們實現了一個可插拔的塊放置策略:將塊副本的放置限制在比較小的,可配置的節點組內。這就使得我們如果選擇合適的組大小,就可以將數據丟失概率降低幾個數量級。我們的策略是使用一個邏輯的機櫃環,每個機櫃又包含一系列的機器,爲原始的block確定一個可放置的機櫃和機器窗口。更細節地內容比如用於計算這些數字的數學函數和腳本可以參考HDFS-1094。我們發現隨着節點組大小的上升,塊丟失的概率會也會增加。在我們的集羣中,我們使用一個(2,5)的節點組,即機櫃的窗口大小是2,機器的窗口大小是5。我們這樣選擇的原因是此時的數據丟失概率大概比默認的塊放置策略小了100倍。


4.4針對實時性負載的性能改進

HDFS最初是爲像MapReduce這樣的高吞吐率系統設計的。它的很多原始設計都是爲了提高吞吐率而不是着重於響應時間。比如,在處理錯誤時,它喜歡進行重試或者進行等待。爲了支持實時性應用,在出錯的情況下提供合理的響應時間成爲HDFS面臨的主要挑戰。


4.4.1RPC超時

一個例子是Hadoop如何處理RPC超時。Hadoop使用TCP發送Hadoop-RPCs。當一個RPC客戶端檢測到一個tcp-socket超時時,不是直接聲明一個RPC超時,而是向RPC服務器發送一個ping請求。如果該服務器仍然是活動的,客戶端會繼續等待響應。這樣做的出發點是,一個RPC服務器可能正在經歷一個通信風暴、一個臨時的高負載、GC產生的停頓,客戶端應該等待同時減少到發給服務器的流量。與之相反的,如果是拋出一個超時異常或者是重試該RPC請求可能會導致任務不必要地失敗或者給RPC服務器增加額外的負載。

 

然而,無限等待會給那些具有實時性需求的應用帶來負面的影響。一個HDFS客戶端間或地向某個Datanode發起一個RPC請求,如果該Datanode不能及時響應就會很糟糕,該客戶端會卡在該RPC調用上。一個更好的策略是快速的失敗,然後爲讀或寫操作嘗試另一個DataNode。因此,我們在啓動與服務器的RPC調用時,提供一個可以指定PRC超時時間的設置選項。


4.4.2Recover File Lease

另一個改進是可以快速撤銷寫者租約。HDFS支持一個文件只有一個寫者,NameNode會維護一個租約來保證該語義。存在很多情況,一個應用程序想打開一個之前未被幹淨地關閉地文件進行讀取{?租約會阻塞讀者?那麼下文中的併發讀者又是如何處理的呢,或者說能否用併發讀者解決這個問題?是否是筆誤呢,感覺讀取應該換成寫入,根據HDFS最新的論文內容,實際上HDFS是支持對於一個正在寫入的文件的讀取的。也可能針對的是不同版本。}在此之前,可以通過重複地在該文件上調用HDFS-append直到成功來實現地{!即可以通過append空內容來首先使它的軟租約過期,之後就可以讀取了。關於這點也有疑問。參見HDFS-1142HADOOP-1700 }。Append操作會觸發文件的軟租約過期。這樣應用程序在HDFS NameNode釋放該文件租約前,就必須要等待一個最小的軟租約過期週期(默認是一分鐘)。其次,HDFS-append操作引入了一些不必要的開銷,比如建立write pipeline通常涉及到不止一個地DataNode。當錯誤發生時,一個pipeline的建立可能會高達10分鐘。

 

爲了避免HDFS-append開銷,我們增加了一個輕量級的HDFS API調用recoverLease,通過它可以顯式地釋放一個文件的租約。當NameNode接受到一個recoverLease請求,它會立即將文件的租約持有者改變成它自己。然後開始租約恢復過程。recoverLease rpc返回一個狀態值表示租約恢復是否成功。應用程序在嘗試讀取文件之前需要等待來自recoverLease成功的返回碼。


4.4.3本地副本讀取

有時應用程序可能會因爲擴展性和性能的原因而想把數據存儲在HDFS上。然而,一個HDFS文件上的讀寫會比本地文件的讀寫具有數量級上的高延遲。爲了緩和這個問題,我們對HDFS客戶端進行了一個改進,如果檢測到本地包含數據的一個副本,就直接對本地副本進行讀取而不再通過DataNode進行傳輸。這個改進爲使用HBase的某個工作負載帶來了雙倍的性能提升。


4.5新Features
4.5.1HDFS sync

Hflush/sync對於HBase和Scribe來說都是一個重要的操作。它將緩存在客戶端的寫入數據推送到write pipeline中。使得數據對於新的讀者都是可見地,同時增強了在客戶端或者pipeline中的DataNode出錯時的數據持久性。Hflush/sync是一個同步性的操作,這就意味着如果沒有收到write pipeline的接收確認它就不會返回。由於該操作被頻繁調用,因此提高它的效率就是至關重要的。我們已經進行的一個優化是,在Hflush/sync操作等待響應地同時允許後面的寫操作繼續進行。這就大大提高了在HBase和Scribe中當某個特定線程週期性調用Hflush/sync時的寫吞吐率。


4.5.2併發讀者

有些應用需要能夠讀那些正在被寫入的文件的能力。讀者首先與NameNode通信得到文件的元數據信息。由於NameNode沒有該文件的最後那個block的長度的最新信息,客戶端可以從持有其中的一個副本的DataNode處獲取該信息。然後它開始讀取該文件。併發讀者和寫者的挑戰之處在於如何提供最後一個chunk的數據,因爲它的數據內容和校驗和是動態變化的。我們通過按需重新計算最後一個chunk數據的校驗和來解決該問題。


5.HBase產品化(Production HBase)

在本節中,我們會描述我們在Facebook的對HBase進行的某些重要改進,這些改進主要涉及到正確性、持久性、可用性及性能。


5.1ACID保證

應用開發者會期望它們的數據庫系統能提供ACID保證,或者是某些近似於它的保證。事實上,強一致性保證也是我們對HBase的早期評估中,所認爲的一個優勢之處。現有的類MVCC的讀寫一致性控制(RWCC)提供了足夠的隔離性保證,同時HDFS的HLog(write ahead log)提供了足夠的持久性保證。然而,還需要進行一些改動以保證HBase可以實現我們需要的ACID保證中的行級別的原子性及一致性。


5.1.1原子性

第一步就是需要保證行級別的原子性。RWCC提供了大部分的保證,然而在節點失敗的情況下有可能喪失這些保證。最初,一個單行事務中的多個entires會被按順序寫入HLog。如果一個RegionServer在寫入時掛掉,這個事務就有可能只被部分地寫入了。通過使用一種新的日誌事務(WALEdit),可以保證每個寫入事務要麼完整完成要麼根本不寫入。


5.1.2一致性

HDFS爲HBase提供備份機制,因此針對我們的應用的HBase的大多數強一致性需求也是由它處理的。在寫的時候,HDFS建立一個連接每個副本的pipeline,所有的副本必須對發送給它的數據進行確認。在得到一個響應或者失敗通知之前HBase不會進行下一步的操作。通過使用序列號,NameNode可以識別出任何行爲異常的副本同時排除掉它們。在方便的時候,NameNode會花一些時間進行文件的恢復。對於HLog來說,在它不斷增長的情況下維護它的一致性和持久性是絕對必需的,一旦檢測到即使僅是一個HDFS副本寫入失敗HBase也必須立即獲取新的blocks重新進行寫入。

 

HDFS也針對數據損壞提供一些保護。在讀取一個HDFS block時,會執行校驗和驗證,在校驗失敗時,整個block會被丟棄。數據丟棄很少會成爲問題,因爲對於這份數據還有其他兩個副本。需要添加一些額外的功能來保證當所有的3份副本都包含損壞數據時,這些blocks依然可以被用於事後的檢查分析{!不能被簡單的刪除丟棄,應該保留它們並記錄一些必要的信息,以保證事後能夠方便地找到它們進行分析}。


5.2可用性改進
5.2.1重寫HBase Master

在通過kill testing進行HBase regions下線測試時,我們發現了很多問題。很快我們意識到問題的根源:整個集羣的瞬時狀態僅僅保存在了HBase master的內存中。在失去該master的同時,這個狀態也丟失了。於是,我們着手去進行HBase master的重寫工作。此次重寫的關鍵部分在於將region分配信息從master的內存狀態中移到Zookeeper中。因爲Zookeeper會至少寫入到半數以上的節點中,這樣這個瞬時狀態在master發生故障恢復時也不會丟失,同時也允許多個服務器的失敗。


5.2.2在線升級

導致集羣停機的最大原因不是隨機的服務器失敗,而是系統維護。爲最小化停機時間我們碰到了很多問題。

 

首先,隨着時間的推移RegionServers在一個停機請求產生後間歇性地出現需要幾分鐘才能關閉的情況。這種間歇性的問題是由長的compaction週期造成的。爲了解決這個問題,我們讓compaction變成可中斷的,這樣就能及時結束然後做出響應。這使得RegionServers的停機時間降低到秒級別,同時對於整個集羣的停機時間給出了一個合理可接受的上界。

 

另一個可用性改進是滾動式重啓。最初,HBase只能停下整個集羣然後啓動升級。我們添加了滾動式的重啓腳本一次對一個服務器執行軟件升級。因爲master可以在某個RegionServer停機的情況下自動地重新分配它上面的regions,這就可以用來最小化用戶能感受到的停機時間。順便提一下,在滾動式重啓過程中,發現很多與region離線及重分配相關的bug,而我們因與Zookeeper集成進行的master重寫幫助解決了這裏的很多問題。


5.2.3分佈式的日誌切分

當一個RegionServer掛掉的時候,它上面的regions在可以被重新打開及讀寫之前,該server上的HLog必須被切分然後進行replay。在日誌在剩餘的RegionServers上replay之前,會由Master負責對日誌的切分。這是整個恢復過程中最慢的一部分,因爲每個server通常有很多的HLog文件,但實際上它是可以並行進行的。利用Zookeeper進行管理,可以在多個RegionServers進行切分,master現在只是負責協調一個分佈式的日誌切分任務。這將恢復時間降低了一個數量級,同時也允許RegionServers可以保留更多的HLogs而不用擔心會影響故障恢復的性能。


5.3性能改進

HBase中的數據插入針對寫性能進行了專門優化,通過以可能的冗餘讀爲代價將寫操作轉化爲順序寫。一個數據事務會首先被寫入一個commit log中,然後應用到一個稱爲MemStore的內存cache中。當MemStore達到一定閾值後,會以HFile的格式寫出去。HFile是不可變的HDFS文件,內部包含一系列有序的key-value對。不是修改現有的HFile,而是在每次flush時寫出新的HFile並且將其加入到以region爲單位的列表中。讀請求需要並行地在多個HFile上進行,通過對它們進行歸併聚合得到最終結果。爲了提高效率,這些HFile需要進行週期性地compact,或者歸併到一塊以減少讀性能的降低。


5.3.1Compaction

讀性能與一個region內的文件數相關,因此關鍵在於要有一個良好優化的compaction算法。更嚴重的是,如果compaction算法沒有進行合理的調整,網絡IO性能也會受到嚴重的影響。最重要的是我們需要保證爲我們的使用場景選擇了一個有效的compaction算法。{!HBase最新的compaction算法可以參考HBASE-3209}

 

最初的compactions根據它們是minor還是major分成了兩個獨立的代碼路徑。Minor compactions會基於大小選擇所有文件中的一個子集進行,而基於時間的major compactions則無條件地對所有文件進行compactions。在此之前,只有major compactions會處理刪除、覆蓋,進行過期數據的清洗,這就意味着minor compactions會使得HFile具有不必要地大小,這會降低block cache的效率,同時也會影響未來的compactions效率。通過整合代碼路徑,實現了代碼的簡化,同時也讓文件儘量地小。

 

下一個任務就是要提高compactions算法性能了。在發佈之後,我們注意到put和sync延遲非常高。我們發現存在一種異常情況,在這種情況下,一個1GB的文件會與其他3個5MB的文件進行合然後生成了一個稍微大些的文件。實際上着浪費了大量的網絡IO。該問題的產生是由於現有的compactions算法在3個HFile達到minor compactions的觸發條件後,會無條件地對前4個HFile進行minor compactions。解決方案就是對那些達到一定大小的文件停止這種無條件地compacting,同時在候選文件不足時跳過compaction。之後,我們的put延遲從25毫秒降到了3毫秒。

 

我們也在致力於改進決定是否啓動compaction算法ratio參數的大小{!HBase中有個參數hbase.hstore.compaction.ratio 用於決定某文件是否進行compaction}。最初的時候,compaction算法會根據文件年齡從老到新進行排序,然後比較相鄰的文件。如果較老的那個文件小於較新的那個文件的2倍大小,那麼compaction算法就會將該文件包含在內,然後繼續迭代。然而,該算法在HFile文件數目和大小增長很快的情況下表現出次優的行爲{!在這種情況下,新產生的文件的大小可能都是差不多的,這樣它們可能就沒法滿足上面的compaction條件,而無法參與compaction}。作爲改進,如果某個文件大小,小於比它新的所有文件的總大小的2倍,我們就把它包括進來。這可能產生一種不平穩的狀態,因爲一個老的文件可能會是下一個比它新的文件的4倍,因此即使是維持在50%的compaction率的情況下,仍可能得到一個比較陡峭的compaction執行曲線。


5.3.2讀操作優化

正如討論的那樣,讀操作性能需要通過保持region內的文件數在一個較低的水平上來降低隨機的IO操作。除了利用compaction來保證磁盤上的文件數,對於某些查詢來說跳過某些特定的文件也是可能的,這也能減少IO操作。

 

Bloom filters提供了一種具有高效地空間利用率及常數級時間開銷的方法,來檢查某個給定的行或者行列是否存在於某給定的HFile中。因爲每個HFile的那個元數據塊(可選的)是被順序地寫入到文件尾部,額外的bloom filters可以很容易地添加到裏面而無需太大的變更。通過在寫回磁盤及緩存在內存的時候使用folding{!folding本意是摺疊,實際上是對bloom filter所佔用的空間進行的一種優化,比如我們可以把一個具有2N個bit的bloom filter摺疊成N個bit的,只需要按位進行或操作,同時在判斷時注意做一個轉換,就可以了。這樣我們就可以比如看看當前的bloom filter的位使用狀況是否很稀疏,如果很稀疏我們完全可以進行摺疊以降低它佔用的空間。具體實現可以參考ByteBloomFilter.java},可以讓每個bloom filter的空間開銷儘量地小。對於那些特定行或/和列的查詢,通過檢查每個HFile的bloom filter就可以完全地跳過那些不包含它們的那些文件。

 

對於存儲在HBase的某些基於時間序列或者包含一個特定的已知時間戳的數據來說,可以添加一個特殊的時間戳文件選擇算法。因爲時間總是在向前流動,因此數據的插入時間通常要比它的時間戳還要晚,每個HFile將會自動生成那些處於某個固定的時間間隔內的值。這些信息可以保存在HFile的元數據中,在進行特定的時間戳或者時間區間內的查詢時,就可以檢查文件的時間窗口與之是否相交,就可以直接跳過那些與之沒有重疊區間的文件。

 

通過HDFS 本地文件讀顯著地提高了讀操作性能,因此讓那些regions駐留在它們的文件本身所在的物理節點上是至關重要的。我們已經進行了一些改進來保證這種集羣上的region的分配策略,同時在節點重啓時也儘量去維護這種locality。


6.部署及運維經驗

在過去的這些年裏,我們從最初運行的一個具有10節點的HBase測試集羣到很多運行着數千個節點的集羣。這些部署已經爲數百萬的用戶提供實時在線的產品服務。在此期間,我們也對核心軟件(HBase/HDFS)及運行在HBase之上的應用程序邏輯進行了快速地迭代改進。在這樣一個充滿流動性的環境中,我們的駕馭高質量軟件、正確地部署、運行系統監控以及檢測異常和在最小停機時間下進行fix的能力,都是至關重要的。這一節我們會深入到我們在這些演化過程中的實踐經驗及相關工具。


6.1測試

在我們最初設計HBase解決方案時,就擔心過代碼的穩定性。我們首先需要測試開源代碼的穩定性和耐用性,以保證我們未來進行變更時的穩定性。最終,我們寫了一個HBase測試程序。該測試程序可以爲HBase寫入生成確定性的或者是隨機性的數據。該測試程序會將數據寫入到HBase集羣以及並行地讀取及驗證它所添加的數據。我們還會繼續對該測試程序進行改進以支持在集羣中隨機選擇以及kill掉進程,驗證那些成功返回的數據庫事務是否已被真地寫入。這幫助我們發現了很多問題,也是我們測試變更的首要方法。

 

儘管我們的集羣環境由很多具有分佈式行爲模式的服務器組成,我們的local開發驗證環境通常是由單元測試和單機版環境組成。我們會關注那些在單機版與真實的集羣環境中不一致的地方。我們建立了一個稱爲HBase Verify的工具來在單個服務器上運行簡單的CRUD{!即增刪改查,create、retrieve、update、delete}工作負載。這使得我們在幾分鐘內就可以執行一些簡單的API調用實驗及運行一些負載測試。這個工具甚至對於我們的dark launch集羣(算法在這些集羣上首次進行大規模的評估)來說都是非常重要的。


6.2監控及工具

當我們具有了很多的HBase產品化使用經驗之後,很明顯地我們面臨的首要問題是在對regions的分配上RegionServers間的產生不一致性。兩個RegionServers最終可能會負責同一個region的服務,或者是某個region可能會處於未分配的狀態。這些問題是由存儲在不同位置上的,關於regions狀態的元數據的不一致性導致的:存儲在HBase以及ZooKeeper的META region,存儲在HDFS上以及RegionServers的內存中的region對應的那些文件。儘管很多的這類問題都可以系統化地解決,同時可以作爲HBase Master重寫(見5.2.1節)的一部分進行進一步的測試,我們仍然擔心某些在產品環境下暴露出的邊界問題。最終,我們建立了HBCK作爲一種驗證這些不同的元數據來源的一致性的數據庫級的FSCK{!FileSystemCheck,在linux中fsck是一種檢查文件系統一致性的工具}工具。對於普通的不一致性,我們添加一個HBCK ‘fix’配置項來清空內存狀態,讓HMaster來重新分配不一致的region。目前,我們幾乎每天都在我們的生產機器上持續運行HBCK以儘快地發現問題。

 

對於集羣監控來說,一個很重要的組件就是操作指標(operational metrics)。尤其是與HMaster和Zookeeper metrics相比,RegionServer metrics對於評估集羣健康狀況更有用處。HBase已經通過JMX導出了大量的metrics。然而這些metrics基本上都是面向短期運行的那些操作比如日誌寫,RPC請求。我們需要添加一些長期運行的一些事件比如compactions,flushes,log splits。另一個比較關鍵的監控信息就是版本信息。通常我們的多個集羣具有不同的版本。在一個集羣出現了crash時,我們需要知道它所特有的那些功能。而且滾動式的更新會導致運行中的版本跟已安裝的版本並不一定是相同的。因此我們需要記住這兩個版本,以及他們出現差異的時間。


6.3手動與自動化Splitting

在學習一個新系統時,我們需要確定哪些features是我們需要立即使用的,哪些features是可以選擇不採用的。HBase提供了一個稱爲自動化splitting的feature,它會在一個region增大到一定程度時將它劃分成2個regions。我們認爲對於我們的使用場景來說,自動化splitting是可以不要的,同時我們開發一個手動的splitting工具代替它。在table創建時,我們提前將table分割成給定數目的等大小的regions。在平均region大小變得太大時,我們可以啓動針對這些regions的滾動式的splits。我們發現這種協議帶來了很多好處。

 

因爲我們的regions基本上都是均勻地增長的,因此對於自動化的splitting來說很容易引起split和compaction風暴,因爲所有的regions很可能在同一時間達到相同的數據大小。通過手動的splits,我們可以將splits操作交錯安排到不同的時間裏,這樣也可以將由splitting進程產生的網絡IO負載平攤開來。這就最小化了對產品工作負載的影響。

 

因爲在任何給定的時間點上,regions的數目都是可知的,這樣長期的debugging和profiling就很簡單。因爲如果regions一直在進行splitting和重命名,就很難通過追蹤日誌來理解那些region層面的問題。

 

在我們最初開始使用HBase時,我們曾經碰過過一些日誌恢復方面的問題,在region故障恢復時,某些日誌文件可能會被落下而處在未處理的狀態。如果regions在那時起沒有進行過分裂,那麼對這種異常的事件事後進行手動的恢復就會很簡單。我們可以找到受影響的region,然後replay未被處理的日誌。在此,我們假設HDFS的垃圾回收機制會爲那些已刪除的文件保留一定的時間週期。

 

有一個比較明顯的問題:手動的splitting有沒有使得HBase喪失某些重要的優勢呢?HBase的其中一個優勢就是splitting是邏輯層面地而不是物理地。底層的共享存儲(HDFS)允許不進行大量數據的移動和拷貝就可以實現regions的重分配。因此,在HBase裏,降低負載的簡單方式不是創建更多的regions而是向集羣中添加更多的機器。Master會自動地將現有的regions重新分配給那些新的RegionServers而不需要手動地介入。此外,自動化的splitting對於那些不具有均勻分佈的應用程序來說很有意義,我們計劃在未來爲這些應用程序使用該特性。


6.4Dark Launch

從一個現有的消息系統中進行遷移,具有一個很大的優勢:在真實環境中測試的能力。在Facebook,廣泛採用一種稱爲”Dark Launch”的測試/部署過程,在這裏,在不改變任何UI的情況下,一些關鍵的後端功能會暴露給某一部分的用戶使用。我們通過使用這種機制來爲某些用戶寫兩份消息流量,一份給老的架構,一份給HBase。這使得我們可以進行一些有用的性能基準測試,發現HBase的瓶頸,取代那種單純的仿真測試及估量方式。即使是在產品發佈之後,我們仍然可能會使用Dark Launch集羣。所有的代碼變更在考慮進行上線之前都會首先在Dark Launch集羣上運行一週。此外,Dark Launch通常會處理我們的生產集羣期望處理的負載規模的2倍。在2倍負載上的長期測試,使得我們可以經受住某些流量突變的情況,同時也可以在進行垂直擴展前幫助驗證HBase能處理某些異常的峯值條件。


6.5Dashboards/ODS集成

我們現在已經有了JMX提供的那些metrics,但是我們還需要一種將這些metrics進行可視化的簡單方式,以及按時間查看集羣的健康狀況。我們決定使用ODS,一個類似於Ganglia的內部工具,用於將一些重要的metrics作成線圖進行可視化。每個集羣都有一個展示面板,內含針對各種平均值及異常值的可視化圖形。繪出最大/最小值是非常重要的,因爲它們通常標識出了具有異常行爲的RegionServers,它們可能導致應用服務器處理隊列產生擁塞。最大的好處是可以實時地觀察統計信息,這樣就可以觀察集羣對不同的工作負載的響應情況(比如運行一個Hadoop MapReduce job或者是進行regions的splitting)。

 

此外,我們還提供兩個跨集羣的展示面板,用於更高級的分析。我們將所有集羣的關鍵統計系統放到一個概覽性的展示面板上來提供更寬廣的狀態視圖。在這個展示面板上,我們還會展示四個針對HBase的圖:Get/Put延遲,Get/Put次數,每Store的文件數,Compaction隊列大小。同時我們也會盡量的展示出集羣版本的差異。我們會在四張圖上展示每個集羣的HMaster版本,HDFS Client版本,NameNode版本,JobTracter版本。這允許我們可以方便的查看版本,找到那些可能存在已知bug的版本。


6.6應用層備份

如何在這種大規模數據集上進行常規備份?一種選擇是將數據從一個HDFS集羣上拷貝到另一個上去。因爲這種策略不是持續進行的,因此在下一次備份事件發生時HDFS上的數據可能已經損壞了。很明顯這是不可接受的。我們決定改進應用程序來連續生成一個可選的應用程序日誌。該日誌會通過Scribe傳輸並保存到一個用於web分析的獨立HDFS集羣上去。這是一個可靠的久經考驗的數據獲取pipeling,特別是我們已經採用這種方式來獲取我們的web應用產生的大量click-log數據並傳送到Hive存儲分析系統。在該應用程序日誌裏的記錄都是冪等的,可以被重複執行多次而不會導致數據丟失。當HBase發生數據丟失事件時,我們就可以重放該日誌流,然後在HBase裏重新生成數據。


6.7Schema變更

HBase當前並不支持對一個現有的table在線進行schema變更。這意味着,如果我們想向現有的某個table中增加一個新的列族(column family),我們必須停止對table的訪問,禁用該table,增加新的列族,將該table恢復上線,然後重啓應用負載。這是一個很嚴重的缺點,因爲通常我們都無法去直接停止我們的工作負載。相反的,我們會爲我們的某些核心的HBase table預先創建一些額外的列族。當前應用程序可能不會向該列族內存儲任何數據,但是可以在以後使用它們。


6.8數據導入

起初,我們採用一個Hadoop job通過常規的數據庫put操作將Message的歷史數據導入到HBase中。當put請求在服務器間傳輸時,該Hadoop job會使網絡IO達到飽和狀態。在進行alpha release時,我們發現這種方式會導致超過30分鐘的嚴重延遲,因爲導入數據與我們的實時流量是混雜在一塊的。這種影響是不可接受的—我們需要一種既能夠爲數百萬的用戶導入數據同時又不能嚴重影響生產系統正常工作的方法。解決方法是採用一種使用壓縮的大批量導入方法。這種大批量導入方法會使用一個map job將數據劃分爲多個regions,然後reducer直接將數據寫成LZO壓縮格式的HFiles。這樣網絡流量主要來源於針對map輸出的shuffle過程。這個問題可以通過對map的中間輸出進行GZIP壓縮來解決。


6.9降低網絡IO

當在產品系統中運行了兩個月後,從dashboards中我們很快意識到我們的應用是網絡IO密集型的。我們需要通過某些方法去分析我們的網絡IO流量到底來源自哪些地方。我們將JMX統計功能與日誌分析相結合來對一個RegionServer 24小時內的整體的網絡IO進行評估。我們發現網絡流量主要由三部分組成:MemStore flush(15%),基於文件大小的minor compactions(38%),基於時間的major compactions(47%)。通過觀察這個比率,我們發現了很多快速優化方法。比如通過簡單地將major compactions的週期從一天增加到一週,就降低了40%的網絡IO。通過關閉某些列族的HLog操作,我們也得到了很大的提升。當然前提是存儲在這些列族中的數據並不需要太高的持久性保證。


7.工作展望

關於Hadoop和HBase在Facebook的應用纔剛剛開始,我們期望對這一套東西不斷的進行迭代,並持續的針對我們的應用進行優化。爲了讓更多的應用來使用HBase,我們也在討論爲它增加二級索引維護及摘要視圖這樣的一些功能。在很多應用場景中,這樣的一些派生數據和視圖都可以異步地進行維護。很多應用場景可以通過在HBase的cache中存儲大量數據來獲益,當然對於HBase的這種改進會佔用大量的物理內存。在這一塊,目前還受限於Java內部Heap的實現方式,我們也正在評估幾種解決方案,比如用Java實現一個slab分配器或者是通過JNI進行內存管理。一個相關的方向是使用flash memory來擴展HBase cache,目前我們也正在探索使用flash memory的各種方式比如FlashCache。最後,因爲我們希望那些採用了跨數據中心的雙工熱備的應用也可以使用Hadoop和HBase,所以我們也在探索一些機制來進行多數據中心的replication和衝突解決。


8.致謝

我們當前的這個Hadoop實時架構是基於過去很多年的工作成果之上的。在此期間,Facebook的很多工作人員爲這些系統做出了很多貢獻和改進。我們要感謝Scott Chen和Ramkumar Vadalli爲Hadoop所做出的很多改進,包括HDFS AvatarNode,HDFS RAID等等。還要感謝Andrew Ryan,Matthew Wetly和Paul Tuckfield在運維,監控,和統計上所做的工作。還要感謝Gautam Roy, Aron Rivin,Prakash Khemani 和 Zheng Shao對存儲系統的各個方面的不斷支持和改進。還要感謝Patrick Kling實習期間爲HDFS HA實現的測試套件。最後一點也是非常重要的一點,我們要感謝我們的用戶們,感謝他們對於系統演化中出現的不穩定性的耐心,以及各種有價值的反饋,正是這些使得我們可以不斷地改進我們的系統。

9.參考文獻

[1] Apache Hadoop. Available at http://hadoop.apache.org

[2] Apache HDFS. Available at http://hadoop.apache.org/hdfs

[3] Apache Hive. Available at http://hive.apache.org

[4] Apache HBase. Available at http://hbase.apache.org

[5] The Google File System.

http://labs.google.com/papers/gfs-sosp2003.pdf

[6] MapReduce: Simplified Data Processing on Large Clusters.

http://labs.google.com/papers/mapreduceosdi04.pdf

[7] BigTable: A Distributed Storage System for Structured Data.

http://labs.google.com/papers/bigtableosdi06.pdf

[8] ZooKeeper: Wait-free coordination for Internet-scale systems.

http://www.usenix.org/events/usenix10/tech/full_papers/Hunt.pdf

[9] Memcached.

http://en.wikipedia.org/wiki/Memcached

[10] Scribe. Available at http://github.com/facebook/scribe/wiki

[11] Building Realtime Insights.

http://www.facebook.com/note.php?note_id=10150103900258920

[12] Seligstein, Joel. 2010. Facebook Messages.

http://www.facebook.com/blog.php?post=452288242130

[13] Patrick O'Neil and Edward Cheng and Dieter Gawlick and

Elizabeth O'Neil. The Log-Structured Merge-Tree (LSMTree)

[14] HDFS-1094.

http://issues.apache.org/jira/browse/HDFS-1094.

        [15] Faacebook Chat.

https://www.facebook.com/note.php?note_id=14218138919

[16] Facebook has the world's largest Hadoop cluster!

http://hadoopblog.blogspot.com/2010/05/facebook-hasworlds-largest-hadoop.html

[17] Fsck. Available at http://en.wikipedia.org/wiki/Fsck

[18] FlashCache. Available at https://github.com/facebook/flashcache


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