運營大規模HDFS叢集必看:系統升級後,怎麼效能反而惡化了?!
一、效能挑戰
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.
重啟叢集以後問題可以得到緩解,但是這個問題需要從根本上考慮如何解決。
二、效能優化
RPC變慢的根源在於HDFS的NameNode吞吐量和效能瓶頸。NameNode存在最大吞吐量限制,每一次寫的請求都會產生排他性“寫鎖”,強制其他任何操作必須在佇列裡等待它完成。
NameNode的RPC queue time指標可以顯示錶達這個系統當前狀態。對此我們主要從程式碼和業務兩方面進行優化。
三、Datanode延遲塊彙報
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。
四、刪除塊個數可配置
由於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
1、獨立叢集模式弊端
在日常HDFS叢集維護過程中,我們發現HDFS叢集獨立執行模式存在著許多弊端:
-
獨立叢集模式運維成本高,上下線機器每次都要制定分配所屬叢集。
-
多獨立叢集模式無非良好均衡資源和請求,經常發現A叢集平時負載要遠遠高於B叢集,這本質上是資源共享利用的問題。
-
單叢集模式效能瓶頸問題。
綜上,我們對現有大叢集獨立執行模式進行了Federation改造。Federation改造的關鍵前提是不同namespace的Cluster ID必須保持一致,否則DN在上報過程中會丟擲異常而註冊失敗。
鑑於我們內部叢集在初始搭建時指定了統一的Cluster ID,所以並沒有在前期再對Cluster ID做額外人工轉換工作。
2、Federation問題解決
在Federation過程中,我們主要遇到了3個問題:
不同叢集拓撲結構不一致導致DN註冊上報錯誤,錯誤如下:
上述錯誤產生的根本原因是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請求
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檢測顯然非常浪費效能,可以設定引數選擇性關閉。
七、小檔案治理
小檔案問題在大規模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的子專案,我們也會持續關注。