唯品会 1000+ 台 Hadoop 集群优化经验
性能挑戰
01
?
HDFS 是一個分布式系統,只要有足夠的資源,可以擴容上千個節點支持100PB以上的集群。我們發現Hadoop集群升級(2.5.0-cdh5.3.2-->2.6.0-cdh5.13.1)以后,NameNode RPC(remote procedure call)queue time在持續的在間隔一周左右性能惡化,在極端環境下出現一個RPC查詢需要等待好幾分鐘的情況,Hive作業出現大量的同一類型錯誤失敗:
Error in org.apache.Hadoop.Hive.ql.exec.mr.MapRedTask. Unable to close file because the last block does not have enough number of replicas.重啟集群以后問題可以得到緩解,但是這個問題需要從根本上考慮如何解決。
?
性能優化
02
?
RPC變慢的根源在于HDFS的NameNode吞吐量和性能瓶頸。NameNode存在最大吞吐量限制,每一次寫的請求都會產生排他性“寫鎖”,強制其他任何操作必須在隊列里等待它完成。NameNode的RPC queue time指標可以顯示表達這個系統當前狀態。對此我們主要從代碼和業務兩方面進行優化。
?
Datanode延遲塊匯報
03
?
1.Datanode的塊匯報
當datanode上新寫完一個塊,默認會立即匯報給namenode。在一個大規模Hadoop集群上,每時每刻都在寫數據,datanode上隨時都會有寫完數據塊然后匯報給namenode的情況。因此namenode會頻繁處理datanode這種快匯報請求,會頻繁地持有鎖,其實非常影響其他rpc的處理和響應時間。
?
2.優化方案
通過延遲快匯報配置可以減少datanode寫完塊后的塊匯報次數,提高namenode處理rpc的響應時間和處理速度。
配置:
<property> <name>dfs.blockreport.incremental.intervalMsec</name> <value>300</value></property>目前我們HDFS集群上此參數配置為300毫秒,就是當datanode新寫一個塊,不是立即匯報給namenode,而是要等待300毫秒,在此時間段內新寫的塊一次性匯報給namenode。
?
刪除塊個數可配置
04
?
由于HDFS的單一鎖設計,NN對于大目錄刪除行為并沒有表現出很好的執行效果,嚴重時甚至會出現長時間block其它應用的正常請求處理。Hadoop新版本引入新結構FoldedTreeSet來存儲DN的塊數據,但是它并不利于update操作,因此刪除問題在升級后的版本中體現更為明顯了。我們也在社區上提了相關issue:https://issues.apache.org/jira/browse/HDFS-13671。
?
后續我們在研究HDFS刪除塊的行為中,發現NN在每次batch刪除塊的時候,是以固定size按照batch方式定期刪除收集到的塊信息。在每次batch間隙,其它請求就有機會得到NN鎖的機會。于是我們考慮到一個改進手段,即是否能讓batch size變得更加靈活可配置化,以此來控制給其它請求得到NN鎖處理的概率。
?
基于這個思路,我們新建了以下配置項,并改動了相關代碼邏輯。???????
<property> <name>dfs.namenode.block.deletion.increment</name> <value>1000</value> <description> The number of block deletion increment. This setting will control the block increment deletion rate to ensure that other waiters on the lock can get in. </description> </property>此優化也已經被我們貢獻到Hadoop社區,相關JIRA鏈接:https://issues.apache.org/jira/browse/HDFS-13831(點擊閱讀原文即可進入頁面)
?
HDFS Federation
05
?
1.獨立集群模式弊端
在日常HDFS集群維護過程中,我們發現HDFS集群獨立運行模式存在著許多弊端:
●獨立集群模式運維成本高,上下線機器每次都要制定分配所屬集群。
●多獨立集群模式無非良好均衡資源和請求,經常發現A集群平時負載要遠遠高于B集群,這本質上是資源共享利用的問題。
●單集群模式性能瓶頸問題。
?
綜上,我們對現有大集群獨立運行模式進行了Federation改造。Federation改造的關鍵前提是不同namespace的Cluster ID必須保持一致,否則DN在上報過程中會拋出異常而注冊失敗。鑒于我們內部集群在初始搭建時指定了統一的Cluster ID,所以并沒有在前期再對Cluster ID做額外人工轉換工作。
?
2.Federation問題解決
在Federation過程中,我們主要遇到了3個問題:
不同集群拓撲結構不一致導致DN注冊上報錯誤,錯誤如下:???????
2019-01-29 14:12:10,821 ERROR [Thread-30] org.apache.Hadoop.HDFS.server.datanode.DataNode: Initialization failed for Block pool BP-1508644862-xx.xx.xx.xx-1493781183457 (Datanode Uuid b8a47300-9fd9-4226-93a1-6649341b3b2c) service to xx.xx.xx.xx:8022 Failed to add /default-rack/xx.xx.xx.xx:50010: You cannot have a rack and a non-rack node at the same level of the network topology.at org.apache.Hadoop.net.NetworkTopology.add(NetworkTopology.java:414)at org.apache.Hadoop.HDFS.server.blockmanagement.DatanodeManager.registerDatanode(DatanodeManager.java:987)at org.apache.Hadoop.HDFS.server.namenode.FSNamesystem.registerDatanode(FSNamesystem.java:5264)at org.apache.Hadoop.HDFS.server.namenode.NameNodeRpcServer.registerDatanode(NameNodeRpcServer.java:1291)at org.apache.Hadoop.HDFS.protocolPB.DatanodeProtocolServerSideTranslatorPB.registerDatanode(DatanodeProtocolServerSideTranslatorPB.java:100)at org.apache.Hadoop.HDFS.protocol.proto.DatanodeProtocolProtos$DatanodeProtocolService$2.callBlockingMethod(DatanodeProtocolProtos.java:29184)???
上述錯誤產生的根本原因是DN在Federation注冊時在不同的namespace擁有不同level層級。后面經過原因排查,是由于我們沒有完全同步好2個集群rack-awareness的腳本映射關系,由配置項net.topology.script.file.name所配置。
?
后續在DN Federation上報過程中,我們又遇到了因為本地du命令不準確導致DN capacity容量double的異常,繼而導致DN無非正常進行寫數據塊行為。因為DN在上報自身capacity容量時,需要依賴于本地系統du命令來計算實際使用空間大小。后面我們對系統du命令進行了校準修復,最后DN能正常Federation上報注冊。
?
如今,我們已經完全打通2個獨立大集群,同時加入第三套NN,來做新的namespace存儲,在未來會對數據進行業務劃分,將數據均衡打散在不同namespace下,充分利用每個namespace下NN的處理能力。
?
另外一個問題是在Federation完成后發現的。因為Federation過程是將已有獨立大集群模式改造成Federation模式,而不是直接搭建新Federation集群模式,我們發現NN元數據膨脹地比較厲害,即使block的元數據沒有發生多大變化,但是實質上DN和block的映射是會得到膨脹的,因此后期馬上對NN的JVM參數進行了相關調整。
?
我們原有主集群的運行模式如下,兩個獨立大集群運作模式:
經Federation改造完成的結構如下,?最終效果是所有datanode向全部三套NN匯報:
客戶端監控以及temp目錄分流,Hive本身降低HDFS請求
06
?
1.HDFS客戶端監控
客戶端監控主要是從HDFS的客戶端角度出發,監控HDFS的rename、create等部分rpc操作或者write這種涉及datanode操作的操作時長。這是補充HDFS服務端rpc監控的手段之一。
?
出發點是,有時服務端這邊的監控比較正常,但是從任務(Hive,spark或者presto)角度來看,發現一些move或者load等操作依舊花費很長時間。這意味著服務端監控僅能夠體現服務端處理性能,并不能很好地衡量整個集群向外提供服務的性能。
上圖是rename的平均時長,考量的是一個文件被rename后的平均時長。
上圖write的平均時長,考量一個只有少量數據的文件被創建時的平均時長,通過這個指標可以評估當前namenode的8022端口以及datanode性能。
?
2.temp目錄分流
從上面分析bip以及bip03的文件操作以及rpc情況來看,可以得出如下兩個結論:
●占用rpc大頭的是 /mr/staging, /tmp/Hive/HDFS/, /bip/developer/vipdm, 其次還有/tmp/Hive/.Hive-staging, ? ? ?/mr/intermediate_done, /bip
●切換 ? ? ?defaultFs, 明顯影響到 /mr/staging, /tmp/Hive/HDFS/ ,/mr/intermediate_done, 也非常明顯影響了rpc。
●如此,對temp目錄進行分流將會很大程度影響集群的rpc情況。
?
解決方案如下:
●在Hive引擎層面(或者在調度層面也ok),平衡切換defaultFs,確保臨時目錄均衡地分布在bip或者bip03上面。
●采用第三個集群,將 ? ? ?/mr/staging, /tmp/Hive/HDFS/, ? ? ?/mr/intermediate_done 遷移到上面,簡而言之,就是把defaultFs設置成第三個集群(最好可以通過Federation進行分流,這樣不會太大影響數據的本地性)。
●使用雙報,通過自動化的方式平衡bip以及bip03的壓力。
?
3.Hive本身降低rpc請求
Hive有很多地方都調用了HDFS的rpc接口,并發出大量rpc請求。如果能夠從Hive的rpc客戶方降低rpc請求,也能夠很大程度緩解HDFS的壓力。
●Hive的insert、create等操作產生的臨時數據,需要統一放到非表下,這樣能夠大量減少在最后rename的操作。
●因為暫時用不上HDFS的Encryption,所以多次的Encryption檢測顯然非常浪費性能,可以設置參數選擇性關閉。
?
小文件治理
07
?
小文件問題在大規模HDFS集群中是經常會遇到的問題。小文件過多引發的各種性能瓶頸在一定程度上影響了集群穩定性。我們采取了以下措施進行優化改善。
?
1.改進措施
●HDFS Federation。相當于橫向擴展namenode的處理能力,增加namenode數量來共同分擔元數據管理的壓力。但這并不十全十美,只是暫時隱藏了小文件多的問題。
●合并小文件。這個方案說起來簡單,卻也并不容易。針對Hive相關任務,針對由歷史任務產生大量小文件的作業,首先使用CombineHiveInputFormat,將多個小文件作為一個整體split,從而減少map數量,然后配置mapred.min.split.size.per.node和mapred.max.split.size增加map處理的文件大小。這個方案我們已經做成可配置化,用定時任務合并用戶歷史作業產生的數據。其次orcfile格式的Hive表,推薦使用CONCATENATE語義,orcfile的合并是stripe級別,節省了解壓和格式化數據的開銷,增加效率。
?
經過一段時間的努力小文件數量得到有效改善,如下圖所示:
?
2. 未來終極解決方案:Hadoop Ozone?
Hadoop Ozone是基于 HDFS 實現的對象存儲服務,支持更大規模數據對象存儲,支持各種對象大小并且擁有 HDFS 的可靠性、一致性和可用性。Ozone的一大目標就是擴展 HDFS,使其支持數十億個對象的存儲。目前這個項目已經成為 Apache Hadoop 的子項目,我們也會持續關注。
?
本文摘自:維技術
總結
以上是生活随笔為你收集整理的唯品会 1000+ 台 Hadoop 集群优化经验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Intellij IDEA 自动生成 s
- 下一篇: 安装了git以后,idea类名颜色的含义