1、背景
2015年10月,通過一段時間的優化與改進,美團點評HDFS集羣穩定性和性能有顯著提高,保證了業務數據存儲量和計算量爆發式增加下的存儲服務質量;然而,隨着集羣規模的發展,單組NameNode組成的集羣也產生了新的瓶頸:node
- 擴展性:根據HDFS NameNode內存全景和HDFS NameNode內存詳解這兩篇文章的說明可知,NameNode內存使用和元數據量正相關。180GB堆內存配置下,元數據量紅線約爲7億,而隨着集羣規模和業務的發展,即便通過小文件合併與數據壓縮,仍然沒法阻止元數據量逐漸接近紅線。
- 可用性:隨着元數據量愈來愈接近7億,CMS GC頻率也愈來愈高,期間也曾發生過一次在CMS GC過程當中因爲大文件getBlocklocation併發太高致使的promotion fail。
- 性能:隨着業務的發展,集羣規模接近2000臺,NameNode響應的RPC QPS也在逐漸提升。愈來愈高併發的讀寫,與NameNode的粗粒度元數據鎖,使NameNode RPC響應延遲和平均RPC隊列長度都在慢慢提升。
- 隔離性:因爲NameNode沒有隔離性設計,單一對NameNode負載太高的應用,會影響到整個集羣的服務能力。
HDFS Federation是Hadoop-0.23.0中爲解決HDFS單點故障而提出的NameNode水平擴展方案。該方案能夠爲HDFS服務建立多個namespace,從而提升集羣的擴展性和隔離性。基於以上背景,咱們在2015年10月發起了HDFS Federation改造項目。apache
HDFS Federation是以客戶端爲核心的解決方案,對Hadoop客戶端影響較大,在落地應用時也有較多的限制,對上層應用模式有較強的依賴。本文分享了在這次改造的過程當中,基於美團點評的業務背景,咱們對HDFS Federation自己作出的改進和對拆分過程的流程化處理,但願能爲須要落地HDFS Federation的同窗提供一個參考。安全
2、上層應用與業務
基礎架構方面,美團點評Hadoop版本爲2.4.1,使用了Kerberos做爲認證支持。相關技術棧中,Spark應用版本包含1.一、1.三、1.四、1.5,同時使用了Zeppelin做爲Spark Notebook的開發工具。在查詢引擎方面Hive有0.13和1.2兩個版本,同時重度依賴Presto和Kylin,除此以外,也對DMLC提供了平臺性支持。數據結構
工具鏈建設方面,基於Hadoop生態,數據平臺組自研了各種平臺工具,其中受Federation影響的部分工具備:架構
- 數倉管理:知足各種Hive表的DDL需求,同時支持UDF和文件上傳建表。
- 原始數據接入:支持日誌抓取和MySQL數據接入數據倉庫。
- 非結構數據開發:支持做業託管,提供MR/Spark做業編譯、管理、測試、部署一站式服務。
- 數倉開發:支持ETL的一站式開發和管理,同時在任務狀態、診斷、SLA保證方面也有強力的支持;針對流程測試以及數據回收進行了隔離,使用統一的test.db和backup.db。
- 調度系統:自研的調度系統支撐了天天數萬個調度做業,準確的處理做業間的強弱依賴關係,有效的保證了按天數據生產。
- 查詢平臺:統一了Hive和Presto的查詢入口。
自研的數據平臺基本覆蓋了90%的數據開發需求,一方面有效的控制了Hadoop客戶端的數量,收緊了用戶入口,對於發放的客戶端,配合Kerberos,也具備很高的掌控力,另外一方面實現了對用戶行爲的源碼級掌控力。併發
數據開發方面,美團點評業務一直持續着爆發式增加,總體集羣規模和數據生產流程增量每一年都接近double。業務發展也推進了組織結構的發展,進而也影響到了相應的大數據資產:app
- 一個Hadoop帳號可能經歷過多個業務線,用戶應用中,對其餘Hadoop帳號的數據進行讀寫、move較爲常見,對這類行爲也沒有進行過梳理和限制。
- 完成平臺接入後,對生產流程管理的規範較多,但對用戶代碼的規範較少,用戶代碼風格多樣。
3、應用與改進
3.1 Federation的侷限性
在解決NameNode擴展能力方面,社區雖然提供了Federation,但這個方案有很強的侷限性:運維
- HDFS路徑Scheme須要變爲ViewFs,ViewFs路徑和其餘Scheme路徑互不兼容,好比DistributedFileSystem沒法處理ViewFs爲Scheme的路徑,也就是說若是啓用,則須要將Hive meta、ETL腳本、MR/Spark做業中的全部HDFS路徑均的scheme改成viewfs。
- 若是將fs.defaultFS的配置從hdfs://ns1/變爲viewfs://ns/,將致使舊代碼異常,經過腳本對用戶上萬個源碼文件的分析,經常使用的HDFS路徑風格多樣,包括hdfs:///user、hdfs://ns1/user、/user等,若是fs.defaultFS有所更改,hdfs:///user將會因爲缺失nameservice變爲非法HDFS路徑。
- ViewFs路徑的掛載方式與Linux有所區別:
- 若是一個路徑聲明瞭掛載,那麼其同級目錄都須要進行掛載,好比/user/path_one掛載到了hdfs://ns1/user/path_one上,那麼/user/path_two也須要在配置中聲明其掛載到哪一個具體的路徑上。
- 若是一個路徑聲明瞭掛載,那麼其子路徑不能再聲明掛載,好比/user/path_one掛載到了hdfs://ns1/user/path_one上,那麼其子路徑也自動而且必須掛載到hdfs://ns1/user/path_one上。
- 一次路徑請求不能跨多個掛載點:
- 因爲HDFS客戶端原有的機制,一個DFSClient只對應一個nameservice,因此一次路徑處理不能轉爲多個nameservice的屢次RPC。
- 對於跨掛載點的讀操做,只根據掛載配置返回假結果。
- 對於跨掛載點的rename(move路徑)操做,會拋出異常。
- Federation架構中,NameNode相互獨立,NameNode元數據、DataNode中塊文件都沒有進行共享,若是要進行拆分,須要使用DistCp,將數據完整的拷貝一份,存儲成本較高;數據先被讀出再寫入三備份的過程,也致使了拷貝效率的低效。
- Federation是改造了客戶端的解決方案,重度依賴客戶端行爲。方案中NameNode相互獨立,對Federation沒有感知。另外HDFS爲Scheme的路徑,不受Federation掛載點影響,也就是說若是對路徑進行了namespace拆分後,若是由於代碼中的路徑或客戶端配置沒有及時更新,致使流程數據寫入老數據路徑,那麼請求依然是合法但不符合預期的。
對其中一些名詞的解釋:
|
3.2 侷限性帶來的問題和解決
3.2.1 Scheme兼容性問題
Scheme的兼容問題要求在上線時全量替換業務方代碼中的路徑,雖然對業務方大多數源碼具備掌控力,可是因爲不可灰度帶來的全量修改帶來的測試、上線、修復工做的成本,全量操做帶來的運維時間,以及對數據生產穩定性的影響都是不能接受的。爲此,以能灰度啓用Federation特性爲目標,對HDFS客戶端進行了修改:機器學習
- 增長了ViewFs和HDFS兩種Scheme路徑的兼容性:
- 修改了org.apache.hadoop.fs.FileSystem.fixRelativePart(Path),該函數在DistributedFileSystem各種請求處理中均有調用,本來用於處理相對路徑,而ViewFileSystem不會調用。在這裏,若是遇到了ViewFs爲Scheme的路徑,則利用ViewFileSystem中的掛載信息返回真正的HDFS路徑。
- 修改了org.apache.hadoop.fs.viewfs.ViewFileSystem.getUriPath(Path),該函數在ViewFileSystem各種請求處理中均有調用,本來用做判斷路徑Scheme爲ViewFs,同時處理相對路徑。一方面,因爲Federation的掛載配置中,只有經過掛載點查詢真實路徑的數據結構,逆向查詢比較複雜,改動也比較大,另外一方面,從運營角度看咱們也不但願維持很是複雜的掛載配置。因此在這裏,作了一個限定,對於HSFS爲Scheme的路徑與其在Federation的掛載點路徑相同,因此在此函數中若是遇到了HDFS爲Scheme的路徑,直接使用org.apache.hadoop.fs.Path.getPathWithoutSchemeAndAuthority(Path)去掉Scheme便可。
- fs.defaultFS變動會對原有代碼帶來影響,可是將其配置爲ViewFs爲Scheme的路徑才能使HDFS Scheme的應用逐漸收斂,所以,咱們增長了用於指定默認namespace的配置fs.defaultNS,使hdfs:///user這樣即便沒有提供Authority的路徑也能路由到正確的NameNode。
針對Scheme侷限性的改造,雖然提升了兼容性,使方案可以進行灰度,但卻使DistributedFileSystem和ViewFileSystem耦合,又增長了一條ViewFileSystem掛載限制,所以只適合在過分期間應用。
3.2.2 掛載配置限制
ViewFs的掛載方式與Linux有所區別,若是徹底繼承現有HDFS不變,則須要很是多的掛在配置項,而且後續每次增長Hive庫、用戶目錄,初期咱們使用了運營手段解決了這個問題:
- 將遷移路徑放到獨立的目錄下,好比/user/hivedata/xx.db,遷移到/ns2/hivedata/xx.db,這樣掛載聲明則不會太過複雜。
- 因爲用戶組路徑大都應用於MR、Spark做業中,修改路徑須要從新編譯,所以初期應用時,只對Hive庫路徑。
- 因爲跨namespace不能進行rename,因此分析NameNode審計日誌,獲得Hive庫路徑和用戶組路徑沒有rename關係的庫,只對這些庫進行遷移。
經過以上三種手段,對於ETL流程這種不須要編譯的代碼,能夠直接替換,對於MR、Spark做業來講推進修改的成本也有所下降。
爲了進一步下降後續拆分紅本,咱們在ETL和做業開發兩個方面提供並推廣了根據庫表信息從Hive meta中取得庫表HDFS路徑的工具,減小了代碼中對庫表路徑的硬編碼。
以上的運維手段,能知足美團側常規的拆分需求,可是隨着點評側數據融合,點評側數據也做爲總體集羣的一個namespace加入進來。然而,咱們對點評側平臺的掌控力沒有深刻到源碼級別,所以沒法統一推進更改HDFS路徑。若是不對掛載邏輯進行修改,在合併重複路徑時,須要將美團側/user路徑合併到點評側/user路徑中,可是因爲跨namespace沒法進行rename,勢必會形成用戶做業的失敗。所以,咱們對掛載邏輯進行了修改,使其同Linux的掛載方式相同。
3.2.3 同namespace,不一樣掛載點不能rename
業務方不少Hive庫表數據會先生成在測試庫表或用戶目錄中,驗證完成後將數據加載到對應時間分區中。在掛載配置中,業務方Hive庫、Hive測試庫、用戶組目錄通常不會掛載到同一目錄下,即便三者在同一namespace下,因爲不一樣掛載點間不能rename的限制,也沒法進行加載。在源碼分析的過程當中,發現如下注釋:
// Note we compare the URIs. the URIs include the link targets. // hence we allow renames across mount links as long as the mount links // point to the same target. if (!resSrc.targetFileSystem.getUri().equals( resDst.targetFileSystem.getUri())) { throw new IOException("Renames across Mount points not supported"); } */ // // Alternate 3 : renames ONLY within the the same mount links. // if (resSrc.targetFileSystem !=resDst.targetFileSystem) { throw new IOException("Renames across Mount points not supported"); }
能夠發現社區是有考慮相同namespace路徑能夠進行rename操做的(註釋掉的緣由沒有找到),所以,咱們將這段邏輯打開,替換掉了「renames ONLY within the the same mount links」。
3.2.4 存儲成本與拷貝效率問題
使用Federation方案時,集羣節點規模爲2000多臺,元數據已達6億,存儲使用已近80%。按照規劃,存儲容量將不足以支撐所有待遷移數據,可是拆成屢次操做,週期和運維成本都比較高,所以咱們開始調研FastCopy。
FastCopy是Facebook開源的數據拷貝方案,它經過如下方式在不增長存儲成本的狀況下對數據進行拷貝:
- 經過getBlockLocation獲取源文件塊分佈。
- 經過ClientProtocol(HDFS包中的接口,下同)建立目標文件。
- 經過ClientProtocol addBlock,在參數中,指定源塊分佈做爲favoredNodes,常規狀況下NameNode會優先選擇favoredNodes中的DataNode做爲塊的保存位置,特殊狀況下(好比存儲空間不足,DataNode負載太高等)也有可能返回不一樣位置。
- 整理源和目標塊位置,使相同DataNode的位置能一一對應。
- 經過ClientDatanodeProtocol向源DataNode發送copyBlock請求。
- 在DataNode中,若是copyBlock請求中的源和目標相同,則經過在Linux文件系統中創建硬鏈的方式完成拷貝,不然經過原有邏輯完成拷貝。
可是,在計劃合入時,該方案也有自身的問題:
- 社區path爲HDFS-2139,一直處於未合入狀態,且當時Patch內容相對Facebook的方案來講,部分細節沒有考慮,例如文件lease,沒法構造硬鏈時的降級,DFS Used的統計問題等。
- Facebook的源碼相對成熟,但其源碼基於0.20(facebookarchive/hadoop-20),已有四年沒有更新,不少源碼發生變化,DFS Used的統計問題也沒有解決。
- 雖然Facebook將FastCopy合入DistCp,但也有部分缺陷:
- 每一個路徑生成一個mapper,每一個mapper只處理一個路徑,若是目錄層次太高,容易致使數據傾斜,若是目錄層次過低,容易產生過多mapper。
- 只對遷移路徑進行屬主同步,其父目錄沒有處理。
- 與DistCp耦合定製比較複雜。
因此,綜合以上內容,咱們完善了HDFS-2139,並更新了issue,在合入Facebook實現的基礎上解決了DFS Used的統計問題;除了這個Patch,咱們也實現了獨立的FastCopy MR做業,解決了上述問題。最終,在拆分時15小時完成14+PB數據拷貝,保證了方案的可行性。
另外須要注意的是,對於HDFS來講,沒法感知哪一個塊是經過硬鏈構造的,所以,一旦源和目標文件同時存在時,開啓balancer,會由於塊的遷移致使存儲使用的增長。所以,遷移期間,通常建議暫停相關namespace的balancer。
3.2.5 重度依賴客戶端
基於以上幾點改進,雖然下降了拆分紅本和兼容性,使Federation的應用成爲可迭代方案,可是若是沒有對客戶端強大的掌控力,客戶端實例不能徹底更新,HDFS路徑硬編碼不能獲得完全梳理,反而會形成數據生產方面的混亂,成爲此方案的掣肘。
通過美團側數據平臺的多年運營,對客戶端以及業務代碼有很是強的掌控力,有效避免了上述問題的發生。
3.3 計算和查詢引擎的問題和解決
一方面,雖然Federation已出現了多年,但Hive、Spark等上層應用對Federation的支持仍然存在問題,另外一方面,隨着應用的逐漸加深,雖然有些問題並非代碼bug,但在美團點評的應用場景下,仍然產生了必定問題。咱們針對這些問題,進行了探索和改進。
3.3.1 安全問題
安全方面,計算引擎(包括MapReduce和Spark)在提交做業時,會向NameNode發送RPC,獲取HDFS Token。在ViewFileSystem中,會向全部namespace串行的申請Token,若是某個namespace的NameNode負載很高,或者發生故障,則任務沒法提交,YARN的ResourceManager在renew Token時,也會受此影響。隨着美團點評的發展YARN做業併發量也在逐漸提升,保存在HDFS上的YARN log因爲QPS太高,被拆分爲獨立的namespace。但因爲其併發和YARN container併發相同,NameNode讀寫壓力仍是很是大,常常致使其RPC隊列打滿,請求超時,進而影響了做業的提交。針對此問題,咱們作出了一下改進:
- container日誌由NodeManager經過impersonate寫入HDFS,這樣客戶端在提交Job時,就不須要YARN log所在namespace的Token。
- ViewFileSystem在獲取Token時,增長了參數,用於指定不獲取哪些namespace的Token。
- 因爲做業並不老是須要全部namespace中的數據,所以當單個namespace故障時,不該當影響其餘namespace數據的讀寫,不然會下降整個集羣的分區容忍性和可用性,ViewFileSystem在獲取Token時,即便失敗,也不影響做業提交,而是在真正訪問數據時做業失敗,這樣在不須要的Token獲取失敗時,不影響做業的運行。
另外,客戶端獲取到的Token會以namespace爲key,保存在一個自定義數據結構中(Credentials)。ResourceManager renew時,遍歷這個數據結構。而NodeManager在拉取JAR包時,根據本地配置中的namespace名去該數據結構中獲取對應Token。所以須要注意的是,雖然namespace配置和服務端不一樣不影響普通HDFS讀寫,但提交做業所使用的namespace配置須要與NodeManager相同,至少會用到的namespace配置須要是一致的。
3.3.2 已存在Patch問題
- https://issues.apache.org/jira/browse/HADOOP-12253
- https://issues.apache.org/jira/browse/TEZ-2600
- https://issues.apache.org/jira/browse/HIVE-11364
- https://issues.apache.org/jira/browse/HIVE-10790
- https://issues.apache.org/jira/browse/HIVE-6152
- https://issues.apache.org/jira/browse/HIVE-11920
- https://issues.apache.org/jira/browse/HIVE-7529
3.3.3 其餘問題
- Hive create table .. as .. 會致使臨時文件所在目錄和表目錄不在同一namespace,致使move結果失敗,目前已修復,思路同HIVE-6152,將臨時文件生成在表目錄中。
- Hive表的元數據中,SERDEPROPERTIES中,可能會存在對HDFS路徑的依賴,在梳理路徑硬編碼時,容易忽略掉。
- Spark 1.1在啓用viewfs時,會產生不兼容問題。
- 開源分佈式機器學習項目DMLC目前也尚不兼容ViewFs。
4、拆分流程與自動化
隨着namespace拆分經驗的積累,其流程也逐漸清晰和明確:
- 當namespace的NameNode逐漸接近瓶頸(包括RPC和元數據量)時,對Hadoop用戶對應的用戶組目錄和Hive庫目錄進行分析,得出元數據量(經過分析fsimage)和一天內RPC量(經過分析審計日誌),進而得出須要拆分的用戶數據。
- 對於須要拆分的數據,分析其和不須要拆分數據的rename關係,若是存在rename關係,則須要從新選擇拆分數據。
- 若是須要,則搭建新namespace環境。
- 關閉相關namespace balancer。
- 根據fsimage,分析出待拆分路徑元數據分佈,得出一個路徑列表,使列表中每一個路徑下的文件塊數基本接近。
- 基於第四步的結果進行首輪拷貝,首輪拷貝中針對不須要比較驗證的狀況做出了優化:FastCopy MR工具會遞歸的拷貝路徑,若是目標路徑已存在說明以前已拷貝成功過,則不進行拷貝。
- 以後進行多輪補充拷貝:經過ls -r獲得文件和目錄列表;拷貝過程當中開啓-delete -update,非遞歸的進行檢測與拷貝,這樣對於源目錄有更新的文件和目錄會進行覆蓋(包括權限和屬主的更新),源目錄新增的目錄和文件會進行拷貝,源目錄刪除的文件和目錄會進行刪除;這樣,能夠會每一層的目錄進行檢測,能夠同步目錄權限和屬主發生的變化,同時也不會產生較大的數據傾斜。
- 準備好新掛載配置,找一個非工做時間,進行最終一輪的操做:
a. 禁止源目錄的權限(FastCopy使用hdfs身份運行不受影響)。
b. 進行最後一輪補充拷貝。
c. 因爲數據大多數狀況下基於硬鏈進行拷貝,因此存在文件長度相同,但內容有問題的可能性極低,拷貝完成後,能夠經過du路徑,校驗並逐漸找到數據長度不一致的文件,進行重考。
d. 對客戶端分發新掛載配置。
e. 對NodeManager分發 新掛載配置,並進行decommission,重啓(YARN已支持recovery)。
f. 更新Hive meta。
g. 開放目標目錄權限。 - 觀察一週,若是沒有問題則刪除源目錄。
- 重啓balancer。
以上是已經固定下來的步驟,其中第一、二、五、六、7步,第8步中的a~c是能夠進行自動化的,這也是後續工做過程當中,有待完善的部分。
5、總結
HDFS Federation做爲以客戶端配置爲核心的NameNode橫向擴容解決方案,對業務背景有較強的依賴,另外一方面方案自己也有較多的侷限性。本文以美團點評實際應用場景出發,介紹了方案侷限性在業務背景下的影響,分享了對侷限性的解決和實施經驗。對HDFS Federation應用到已運營較長時間的大規模HDFS集羣有必定的借鑑意義。
六 參考文獻
- HDFS NameNode內存全景
- HDFS NameNode內存詳解
- HDFS Federation
- HDFS scalability with multiple namenodes
- AN INTRODUCTION TO HDFS FEDERATION
- HDFS Federation設計動機與基本原理
七 做者簡介
俊宏,美團點評離線存儲團隊高級開發工程師,2013年畢業於哈爾濱工程大學,2015年加入美團,負責美團點評HDFS、HBase服務的開發和運維,HBase服務負責人。
美團點評離線團隊,深耕Hadoop生態中HDFS、HBase、CarbonData、Alluxio等泛存儲領域,尤爲在HDFS、HBase方面有大量的源碼和架構改造經驗,致力於爲美團點評提供穩定、高效、易用的大數據存儲服務。
最後發個廣告,美團點評數據平臺中心長期招聘離線計算平臺、實時計算平臺、數據平臺工具鏈與服務等方向的技術專家,有興趣的同窗能夠發送簡歷到liujunhong02#meituan.com。