HDFS Federation在美團點評的應用與改進
HDFS Federation為HDFS系統提供了NameNode橫向擴容能力。然而作為一個已實現多年的解決方案,真正應用到已運行多年的大規模集群時依然存在不少的限制和問題。本文以實際應用場景出發,介紹了HDFS Federation在美團點評的實際應用經驗。
一 背景
2015年10月,經過一段時間的優化與改進,美團點評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改造項目。
HDFS Federation是以客戶端為核心的解決方案,對Hadoop客戶端影響較大,在落地應用時也有較多的限制,對上層應用模式有較強的依賴。本文分享了在此次改造的過程中,基于美團點評的業務背景,我們對HDFS Federation本身做出的改進和對拆分過程的流程化處理,希望能為需要落地HDFS Federation的同學提供一個參考。
二 上層應用與業務
基礎架構方面,美團點評Hadoop版本為2.4.1,使用了Kerberos作為認證支持;相關技術棧中,Spark應用版本包含1.1、1.3、1.4、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。業務發展也推動了組織結構的發展,進而也影響到了相應的大數據資產:
- 一個hadoop賬號可能經歷過多個業務線,用戶應用中,對其他hadoop賬號的數據進行讀寫、move較為常見,對這類行為也沒有進行過梳理和限制;
- 完成平臺接入后,對生產流程管理的規范較多,但對用戶代碼的規范較少,用戶代碼風格多樣;
三 應用與改進 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拆分后,如果因為代碼中的路徑或客戶端配置沒有及時更新,導致流程數據寫入老數據路徑,那么請求依然是合法但不符合預期的;
對其中一些名詞的解釋:
-
在HDFS中namespace是指NameNode中負責管理文件系統中的樹狀目錄結構以及文件與數據塊的映射關系的一層邏輯結構,在Federation方案中,NameNode之間相互隔離,因此社區也用一個namespace來指代Federation中一組獨立的NameNode及其元數據。
-
scheme是URI命名結構([scheme:][//authority][path][?query][#fragment])中的一部分,用于標識URI所使用的協議,HDFS路徑也是一個URI,常見的scheme為hdfs,在Federation的方案中,HDFS路徑scheme為viewfs。
-
掛載點(mount point),它在HDFS Federation中和Linux中的概念近似,指在HDFS客戶端上下文中,將viewfs為scheme的一個路徑,比如viewfs://ns/user,映射到一個具體的HDFS路徑上,比如hdfs://ns2/user,這個路徑可以是任意scheme的HDFS路徑,這樣對于viewfs://ns/user實際上會被轉換為對hdfs://ns2/user的操作。
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的掛載配置中,只有通過掛載點查詢真實路徑的數據結構,逆向查詢比較復雜,改動也比較大;另一方面,從運營角度看我們也不希望維持非常復雜的掛載配置。所以在這里,做了一個限定,對于hdfs為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是非死book開源的數據拷貝方案,他通過以下方式在不增加存儲成本的情況下對數據進行拷貝:
-
通過getBlockLocation獲取源文件塊分布;
-
通過ClientProtocol(HDFS包中的接口,下同)創建目標文件;
-
通過ClientProtocol addBlock,在參數中,指定源塊分布作為favoredNodes,常規情況下NameNode會優先選擇favoredNodes中的DataNode作為塊的保存位置,特殊情況下(比如存儲空間不足,DataNode負載過高等)也有可能返回不同位置;
-
整理源和目標塊位置,使相同DataNode的位置能一一對應;
-
通過ClientDatanodeProtocol向源DataNode發送copyBlock請求;
-
在DataNode中,如果copyBlock請求中的源和目標相同,則通過在Linux文件系統中建立硬鏈的方式完成拷貝,否則通過原有邏輯完成拷貝;
但是,在計劃合入時,該方案也有自身的問題:
-
社區path為HDFS-2139,一直處于未合入狀態,且當時patch內容相對非死book的方案來說,部分細節沒有考慮,例如文件lease,無法構造硬鏈時的降級,DFS Used的統計問題等;
-
非死book的源碼相對成熟,但其源碼基于0.20(非死bookarchive/hadoop-20),已有四年沒有更新,已經有很多源碼發生變化,DFS Used的統計問題也沒有解決;
-
雖然非死book將FastCopy合入DistCp,但也有部分缺陷:
-
每個路徑生成一個maper,每個mapper只處理一個路徑,如果目錄層次過高,容易導致數據傾斜,如果目錄層次太低,容易產生過多mapper;
-
只對遷移路徑進行屬主同步,其父目錄沒有處理;
-
與DistCp耦合定制比較復雜;
-
所以,綜合以上內容,我們完善了HDFS-2139,并更新了issue,在合入非死book實現的基礎上解決了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 安全問題
安全方面,計算引擎包括MR和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;
四 拆分流程與自動化
隨著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;
以上是已經固定下來的步驟,其中第1、2、5、6、7步,第8步中的a~c是可以進行自動化的,這也是后續工作過程中,有待完善的部分。
五 總結
HDFS Federation作為以客戶端配置為核心的NameNode橫向擴容解決方案,對業務背景有較強的依賴,另一方面方案本身也有較多的局限性。本文以美團點評實際應用場景出發,介紹了方案局限性在業務背景下的影響,分享了對局限性的解決和實施經驗。對HDFS Federation應用到已運營較長時間的大規模HDFS集群有一定的借鑒意義。
六 參考文獻
- NameNode內存全景, 2016 .
- NameNode內存及請求情況簡單分析, 2016 .
- HDFS Federation, 2016, .
- HDFS Federation, 2011 .
- AN INTRODUCTION TO HDFS FEDERATION, 2011 .
- HDFS Federation設計動機與基本原理, 2012 .
來自:http://www.infoq.com/cn/articles/application-and-improve-of-hdfs-federation-in-meituan