vivo 互聯(lián)網(wǎng)大數(shù)據(jù)團(tuán)隊-Lv Jia
Hadoop 3.x的第一個穩(wěn)定版本在2017年底就已經(jīng)發(fā)布了功偿,有很多重大的改進(jìn)。
在HDFS方面夕凝,支持了Erasure Coding县钥、More than 2 NameNodes、Router-Based Federation驶臊、Standby NameNode Read、FairCallQueue、Intra-datanode balancer 等新特性澈段。這些新特性在穩(wěn)定性、性能舰攒、成本等多個方面帶來諸多收益败富,我們打算將HDFS集群升級到HDFS 3.x 版本。
本篇文章會介紹我們是如何將CDH 5.14.4 HDFS 2.6.0 滾動升級到HDP-3.1.4.0-315 HDFS 3.1.1版本摩窃,是業(yè)界為數(shù)不多的從CDH集群滾動升級到HDP集群的案例兽叮。在升級中遇到哪些問題?這些問題是如何解決掉的猾愿?本篇文章具有非常高的參考借鑒價值鹦聪。
一、 背景
vivo離線數(shù)倉Hadoop集群基于CDH 5.14.4版本構(gòu)建蒂秘,CDH 5.14.4 Hadoop版本:2.6.0+CDH 5.14.4+2785泽本,是Cloudera公司基于Apache Hadoop 2.6.0版本打入了一些優(yōu)化patch后的Hadoop發(fā)行版。
近幾年隨著vivo業(yè)務(wù)發(fā)展姻僧,數(shù)據(jù)爆炸式增長规丽,離線數(shù)倉HDFS集群從一個擴展到十個,規(guī)模接近萬臺撇贺。隨著 HDFS 集群規(guī)模的增長赌莺,當(dāng)前版本的HDFS的一些痛點問題也暴露出來:
- 在當(dāng)前低版本的HDFS,線上環(huán)境NameNode經(jīng)常出現(xiàn)RPC性能問題松嘶,用戶Hive/Spark離線任務(wù)也會因為NameNode RPC性能變慢導(dǎo)致任務(wù)延遲艘狭。
- 一些RPC性能問題在HDFS 3.x版本均已修復(fù),當(dāng)前只能通過打入HDFS高版本patch的方式解決線上NameNode RPC性能問題。
- 頻繁的patch合并增加了HDFS代碼維護(hù)的復(fù)雜度巢音,每一個patch的上線都需要重啟NameNode或者DataNode遵倦,增加了HDFS集群的運維成本。
- 線上HDFS集群使用viewfs對外提供服務(wù)港谊,公司內(nèi)部業(yè)務(wù)線眾多骇吭,很多業(yè)務(wù)部門申請了獨立的HDFS客戶端訪問離線數(shù)倉集群。當(dāng)修改線上HDFS配置后歧寺,更新HDFS客戶端配置是一件非常耗時且麻煩的事情燥狰。
- HDFS 2.x不支持EC,冷數(shù)據(jù)無法使用EC來降低存儲成本斜筐。
Hadoop 3.x的第一個穩(wěn)定版本在2017年底就已經(jīng)發(fā)布了龙致,有了很多重大的改進(jìn)。在HDFS方面顷链,支持了Erasure Coding目代、More than 2 NameNodes、Router-Based Federation嗤练、Standby NameNode Read榛了、FairCallQueue、Intra-datanode balancer 等新特性煞抬。HDFS 3.x新特性在穩(wěn)定性霜大、性能、成本等多個方面帶來諸多收益革答。
- HDFS Standby NameNode Read战坤、FairCallQueue新特性以及HDFS 3.x NameNode RPC優(yōu)化patch能極大提升我們當(dāng)前版本HDFS集群穩(wěn)定性與RPC性能。
- HDFS RBF替代viewfs残拐,簡化HDFS客戶端配置更新流程途茫,解決線上更新眾多HDFS客戶端配置的痛點問題。
- HDFS EC應(yīng)用冷數(shù)據(jù)存儲溪食,降低存儲成本囊卜。
基于以上痛點問題與收益,我們決定將離線數(shù)倉HDFS集群升級到 HDFS 3.x版本眠菇。
二边败、 HDFS 升級版本選擇
由于我們Hadoop集群基于CDH 5.14.4版本構(gòu)建,我們首先考慮升級到CDH高版本捎废。CDH 7提供HDFS 3.x發(fā)行版,遺憾是CDH 7沒有免費版致燥,我們只能選擇升級到Apache版本或者Hortonworks公司提供的HDP發(fā)行版登疗。
由于Apache Hadoop沒有提供管理工具,對于萬臺規(guī)模的HDFS集群,管理配置辐益、分發(fā)配置極其不方便断傲。因此,我們選擇了Hortonworks HDP發(fā)行版智政,HDFS管理工具選擇Ambari认罩。
Hortonworks提供的最新的穩(wěn)定的免費的Hadoop發(fā)行版為HDP-3.1.4.0-315版本。Hadoop版本為Apache Hadoop 3.1.1版本续捂。
三垦垂、HDFS 升級方案制定
3.1 升級方案
HDFS官方提供兩種升級方案:Express 和 RollingUpgrade。
- **Express **升級過程是停止現(xiàn)有HDFS服務(wù)牙瓢,然后使用新版本HDFS啟動服務(wù)劫拗,會影響線上業(yè)務(wù)正常運行。
- **RollingUpgrade **升級過程是滾動升級矾克,不停服務(wù)页慷,對用戶無感知。
鑒于HDFS停服對業(yè)務(wù)影響較大胁附,我們最終選擇 RollingUpgrade方案酒繁。
3.2 降級方案
RollingUpgrade 方案中, 有兩種回退方式:**Rollback 和 RollingDowngrade **控妻。
- **Rollback **會把HDFS版本連同數(shù)據(jù)狀態(tài)回退到升級前的那一刻 州袒,會造成數(shù)據(jù)丟失。
- RollingDowngrade 只回退HDFS版本饼暑,數(shù)據(jù)不受影響稳析。
我們線上 HDFS 集群是不能容忍數(shù)據(jù)丟失的,我們最終選擇 RollingDowngrade 的回退方案弓叛。
3.3 HDFS 客戶端升級方案
線上 Spark彰居、Hive、Flink 撰筷、OLAP等計算組件重度依賴HDFS Client陈惰,部分計算組件版本過低,需要升級到高版本才能支持HDFS 3.x毕籽,升級HDFS Client有較高風(fēng)險抬闯。
我們在測試環(huán)境經(jīng)過多輪測試,驗證了HDFS 3.x兼容HDFS 2.x client讀寫关筒。
因此溶握,我們本次HDFS升級只升級NameNode、JournalNode蒸播、DataNode組件睡榆,HDFS 2.x Client等YARN升級后再升級萍肆。
3.4 HDFS 滾動升級步驟
RollingUpgrade 升級的操作流程在 Hadoop 官方升級文檔中有介紹,概括起來大致步驟如下:
- JournalNode升級胀屿,使用新版本依次重啟 JournalNode塘揣。
- NameNode升級準(zhǔn)備,生成 rollback fsimage文件宿崭。
- 使用新版本Hadoop重啟 Standby NameNode亲铡,重啟 ZKFC。
- NameNode HA主從切換葡兑,使升級后的 NameNode 變成 Active 節(jié)點奖蔓。
- 使用新版本 Hadoop 重啟另一個 NameNode,重啟 ZKFC铁孵。
- 升級 DataNode锭硼,使用新版本 Hadoop 滾動重啟所有 DataNode 節(jié)點。
- 執(zhí)行 Finalize蜕劝,確認(rèn)HDFS集群升級到新版本檀头。
四、管理工具如何共存
HDFS 2.x集群岖沛,HDFS暑始、YARN、Hive婴削、HBase等組件廊镜,使用CM工具管理。由于只升級HDFS唉俗,HDFS 3.x使用Ambari管理嗤朴,其它組件如YARN、Hive仍然使用CM管理虫溜。HDFS 2.x client不升級雹姊,繼續(xù)使用CM管理。Zookeeper使用原CM部署的ZK衡楞。
具體實現(xiàn):CM Server節(jié)點部署Amari Server吱雏,CM Agent節(jié)點部署Ambari Agent。
如上圖所示瘾境,使用Ambari工具在master/slave節(jié)點部署HDFS 3.x NameNode/DataNode組件歧杏,由于端口沖突,Ambari部署的HDFS 3.x會啟動失敗迷守,不會對線上CM部署的HDFS 2.x集群產(chǎn)生影響犬绒。
HDFS升級開始后,master節(jié)點停止CM JN/ZKFC/NN兑凿,啟動Ambari JN/ZKFC/NN懂更,slave節(jié)點停止CM DN眨业,啟動Ambari DN急膀。HDFS升級的同時實現(xiàn)管理工具從CM切換到Ambari沮协。
五、HDFS 滾動升級降級過程中遇到的問題
5.1 HDFS 社區(qū)已修復(fù)的不兼容問題
HDFS社區(qū)已修復(fù)滾動升級卓嫂、降級過程中關(guān)鍵不兼容的問題慷暂。相關(guān)issue號為:HDFS-13596、 HDFS-14396晨雳、 HDFS-14831行瑞。
【HDFS-13596】: 修復(fù)Active NamNode升級后將EC相關(guān)的數(shù)據(jù)結(jié)構(gòu)寫入EditLog 文件,導(dǎo)致Standby NameNode讀取EditLog 異常直接Shutdown的問題餐禁。
【HDFS-14396】:修復(fù)NameNode升級到HDFS 3.x版本后血久,將EC相關(guān)的數(shù)據(jù)結(jié)構(gòu)寫入Fsimage文件,導(dǎo)致NameNode降級到HDFS 2.x版本識別Fsimage文件異常的問題帮非。
【HDFS-14831】:修復(fù)NameNode升級后對 StringTable 的修改導(dǎo)致HDFS降級后 Fsimage 不兼容問題氧吐。
我們升級的HDP HDFS版本引入了上述三個issue相關(guān)的代碼。除此之外末盔,我們在升級過程中還遇到了其它的不兼容問題:
5.2 JournalNode 升級出現(xiàn) Unknown protocol
JournalNode升級過程中筑舅,出現(xiàn)的問題:
Unknown protocol: org.apache.hadoop.hdfs.qjournal.protocol.InterQJournalProtocol
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.RpcNoSuchProtocolException): Unknown protocol: org.apache.hadoop.hdfs.qjournal.protocol.InterQJournalProtocol
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.getProtocolImpl(ProtobufRpcEngine.java:557)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:596)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1073)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2281)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2277)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1924)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2275)
at org.apache.hadoop.ipc.Client.getRpcResponse(Client.java:1498)
at org.apache.hadoop.ipc.Client.call(Client.java:1444)
at org.apache.hadoop.ipc.Client.call(Client.java:1354)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:228)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:116)
at com.sun.proxy.$Proxy14.getEditLogManifestFromJournal(Unknown Source)
at org.apache.hadoop.hdfs.qjournal.protocolPB.InterQJournalProtocolTranslatorPB.getEditLogManifestFromJournal(InterQJournalProtocolTranslatorPB.java:75)
at org.apache.hadoop.hdfs.qjournal.server.JournalNodeSyncer.syncWithJournalAtIndex(JournalNodeSyncer.java:250)
at org.apache.hadoop.hdfs.qjournal.server.JournalNodeSyncer.syncJournals(JournalNodeSyncer.java:226)
at org.apache.hadoop.hdfs.qjournal.server.JournalNodeSyncer.lambda$startSyncJournalsDaemon$0(JournalNodeSyncer.java:186)
at java.lang.Thread.run(Thread.java:748)
報錯原因:HDFS 3.x新增了InterQJournalProtocol,新增加的InterQJournalProtocol用于JournalNode之間同步舊的edits數(shù)據(jù)陨舱。
HDFS-14942 對此問題進(jìn)行了優(yōu)化翠拣,日志級別從ERROR改成DEBUG。此問題不影響升級游盲,當(dāng)三個HDFS 2.x JN全部升級為HDFS 3.x JN時误墓,JN之間能正常同步數(shù)據(jù)。
5.3 NameNode升級DatanodeProtocol.proto不兼容
NameNode升級后益缎,DatanodeProtocol.proto不兼容谜慌,導(dǎo)致Datanode BlockReport 無法進(jìn)行。
(1)HDFS 2.6.0 版本
DatanodeProtocol.proto
message HeartbeatResponseProto {
repeated DatanodeCommandProto cmds = 1; // Returned commands can be null
required NNHAStatusHeartbeatProto haStatus = 2;
optional RollingUpgradeStatusProto rollingUpgradeStatus = 3;
optional uint64 fullBlockReportLeaseId = 4 [ default = 0 ];
optional RollingUpgradeStatusProto rollingUpgradeStatusV2 = 5;
}
(2)HDFS 3.1.1版本
DatanodeProtocol.proto
message HeartbeatResponseProto {
repeated DatanodeCommandProto cmds = 1; // Returned commands can be null
required NNHAStatusHeartbeatProto haStatus = 2;
optional RollingUpgradeStatusProto rollingUpgradeStatus = 3;
optional RollingUpgradeStatusProto rollingUpgradeStatusV2 = 4;
optional uint64 fullBlockReportLeaseId = 5 [ default = 0 ];
}
我們可以看到兩個版本 HeartbeatResponseProto 的第4链峭、5個參數(shù)位置調(diào)換了畦娄。
這個問題的原因在于,Hadoop 3.1.1 版本commit了 HDFS-9788弊仪,用來解決HDFS升級時兼容低版本問題熙卡,而 HDFS 2.6.0 版本沒有commit ,導(dǎo)致了DatanodeProtocol.proto不兼容励饵。
HDFS升級過程中驳癌,不需要兼容低版本HDFS,只需要兼容低版本HDFS client役听。
因此颓鲜,HDFS 3.x不需要 HDFS-9788 兼容低版本的功能表窘,我們在Hadoop 3.1.1 版本回退了 HDFS-9788 的修改來保持和HDFS 2.6.0 版本的DatanodeProtocol.proto兼容。
5.4 NameNode升級layoutVersion不兼容
NameNode升級后甜滨,NameNode layoutVersion改變乐严,導(dǎo)致EditLog不兼容,HDFS 3.x降級到HDFS 2.x NameNode 無法啟動衣摩。
2021-04-12 20:15:39,571 ERROR org.apache.hadoop.hdfs.server.namenode.EditLogInputStream: caught exception initializing XXX:8480/getJournal
id=test-53-39&segmentTxId=371054&storageInfo=-60%3A1589021536%3A0%3Acluster7
org.apache.hadoop.hdfs.server.namenode.EditLogFileInputStream$LogHeaderCorruptException: Unexpected version of the file system log file: -64. Current version = -60.
at org.apache.hadoop.hdfs.server.namenode.EditLogFileInputStream.readLogVersion(EditLogFileInputStream.java:397)
at org.apache.hadoop.hdfs.server.namenode.EditLogFileInputStream.init(EditLogFileInputStream.java:146)
at org.apache.hadoop.hdfs.server.namenode.EditLogFileInputStream.nextopImpl(EditLogFileInputStream.java:192)
at org.apache.hadoop.hdfs.server.namenode.EditLogFileInputStream.nextop(EditLogFileInputStream.java:250)
at org.apache.hadoop.hdfs.server.namenode.EditLogInputStream.read0p(EditLogInputStream.java:85)
at org.apache.hadoop.hdfs.server.namenode.EditLogInputStream.skipUntil(EditLogInputStream.java:151)
at org.apache.hadoop.hdfs.server.namenode.RedundantEditLogInputStream.next0p(RedundantEditLogInputStream.java:178)
at org.apache.hadoop.hdfs.server.namenode.EditLogInputStream.readop(EditLogInputStream.java:85)
at org.apache.hadoop.hdfs.server.namenode.EditLogInputStream.skipUntil(EditLogInputStream.java:151)
at org.apache.hadoop.hdfs.server.namenode.RedundantEditLogInputStream.next0p(RedundantEditLogInputStream.java:178)
at org.apache.hadoop.hdfs.server.namenode.EditLogInputStream.read0p(EditLogInputStream.java:85)
at org.apache.hadoop.hdfs.server.namenode.FSEditLogLoader.LoadEditRecords(FSEditLogLoader.java:188)
at org.apache.hadoop.hdfs.server.namenode.FSEditLogLoader.LoadFSEdits(FSEditLogLoader.java:141)
at org.apache.hadoop.hdfs.server.namenode.FSImage.loadEdits(FSImage.java:903)
at org.apache.hadoop.hdfs.server.namenode.FSImage.LoadFSImage(FSImage.java:756)
at org.apache.hadoop.hdfs.server.namenode.FSImage.recoverTransitionRead(FSImage.java:324)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.LoadFSImage(FSNamesystem.java:1150)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.LoadFromDisk(FSNamesystem.java:797)
at org.apache.hadoop.hdfs.server.namenode.NameNode.LoadNamesystem (NameNode.java:614)
at org.apache.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:676)
at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:844)
at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:823)
at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode (NameNode.java:1547)
at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1615)
HDFS 2.6.0升級到HDFS 3.1.1昂验,NameNode layoutVersion值 -60 變更成 -64。要解決這個問題艾扮,首先搞清楚NameNode layoutVersion什么情況下會變更既琴?
HDFS版本升級引入新特性,NameNode layoutVersion跟隨新特性變更泡嘴。Hadoop官方升級文檔指出甫恩,HDFS滾動升級過程中要禁用新特性,保證升級過程中l(wèi)ayoutVersion不變酌予,升級后的HDFS 3.x版本才能回退到HDFS 2.x版本磺箕。
接下來,找出HDFS 2.6.0升級到HDFS 3.1.1引入了哪一個新特性導(dǎo)致namenode layoutVersion變更霎终?查看 HDFS-5223滞磺、HDFS-8432、HDFS-3107相關(guān)issue莱褒,HDFS 2.7.0版本引入了truncate功能击困,NameNode layoutVersion變成 -61。查看HDFS 3.x版本NameNodeLayoutVersion代碼:
NameNodeLayoutVersion
public enum Feature implements LayoutFeature {
ROLLING_UPGRADE(-55, -53, -55, "Support rolling upgrade", false),
EDITLOG_LENGTH(-56, -56, "Add length field to every edit log op"),
XATTRS(-57, -57, "Extended attributes"),
CREATE_OVERWRITE(-58, -58, "Use single editlog record for " +
"creating file with overwrite"),
XATTRS_NAMESPACE_EXT(-59, -59, "Increase number of xattr namespaces"),
BLOCK_STORAGE_POLICY(-60, -60, "Block Storage policy"),
TRUNCATE(-61, -61, "Truncate"),
APPEND_NEW_BLOCK(-62, -61, "Support appending to new block"),
QUOTA_BY_STORAGE_TYPE(-63, -61, "Support quota for specific storage types"),
ERASURE_CODING(-64, -61, "Support erasure coding");
TRUNCATE广凸、APPEND_NEW_BLOCK阅茶、QUOTA_BY_STORAGE_TYPE、ERASURE_CODING 四個Feature設(shè)置了minCompatLV為-61谅海。
查看最終NameNode layoutVersion取值邏輯:
FSNamesystem
static int getEffectiveLayoutVersion(boolean isRollingUpgrade, int storageLV,
int minCompatLV, int currentLV) {
if (isRollingUpgrade) {
if (storageLV <= minCompatLV) {
// The prior layout version satisfies the minimum compatible layout
// version of the current software. Keep reporting the prior layout
// as the effective one. Downgrade is possible.
return storageLV;
}
}
// The current software cannot satisfy the layout version of the prior
// software. Proceed with using the current layout version.
return currentLV;
}
getEffectiveLayoutVersion獲取最終生效的layoutVersion脸哀,storageLV是當(dāng)前HDFS 2.6.0版本layoutVersion -60,minCompatLV是 -61扭吁,currentLV是升級后的HDFS 3.1.1版本layoutVersion -64撞蜂。
從代碼判斷邏輯可以看出,HDFS 2.6.0版本layoutVersion -60 小于等于minCompatLV是 -61不成立侥袜,因此蝌诡,升級到HDFS 3.1.1版本后,namenode layoutVersion的取值為currentLV -64枫吧。
從上述代碼分析可以看出浦旱,HDFS 2.7.0版本引入了truncate功能后,HDFS社區(qū)只支持HDFS 3.x 降級到HDFS 2.7版本的NameNode layoutVersion是兼容的九杂。
我們對HDFS truncate功能進(jìn)行評估颁湖,結(jié)合業(yè)務(wù)場景分析宣蠕,我們vivo內(nèi)部離線分析暫時沒有使用HDFS truncate功能的場景∩啵基于此抢蚀,我們修改了HDFS 3.1.1版本的minCompatLV為 -60,用來支持HDFS 2.6.0升級到HDFS 3.1.1版本后能夠降級到HDFS 2.6.0涎永。
minCompatLV修改為-60:
NameNodeLayoutVersion
public enum Feature implements LayoutFeature {
ROLLING_UPGRADE(-55, -53, -55, "Support rolling upgrade", false),
EDITLOG_LENGTH(-56, -56, "Add length field to every edit log op"),
XATTRS(-57, -57, "Extended attributes"),
CREATE_OVERWRITE(-58, -58, "Use single editlog record for " +
"creating file with overwrite"),
XATTRS_NAMESPACE_EXT(-59, -59, "Increase number of xattr namespaces"),
BLOCK_STORAGE_POLICY(-60, -60, "Block Storage policy"),
TRUNCATE(-61, -60, "Truncate"),
APPEND_NEW_BLOCK(-62, -60, "Support appending to new block"),
QUOTA_BY_STORAGE_TYPE(-63, -60, "Support quota for specific storage types"),
ERASURE_CODING(-64, -60, "Support erasure coding");
5.5 DataNode升級layoutVersion不兼容
DataNode升級后思币,DataNode layoutVersion不兼容,HDFS 3.x DataNode降級到HDFS 2.x DataNode無法啟動羡微。
2021-04-19 10:41:01,144 WARN org.apache.hadoop.hdfs.server.common.Storage: Failed to add storage directory [DISK]file:/data/dfs/dn/
org.apache.hadoop.hdfs.server.common.IncorrectVersionException: Unexpected version of storage directory /data/dfs/dn. Reported: -57. Expecting = -56.
at org.apache.hadoop.hdfs.server.common.StorageInfo.setLayoutVersion(StorageInfo.java:178)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.setFieldsFromProperties(DataStorage.java:665)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.setFieldsFromProperties(DataStorage.java:657)
at org.apache.hadoop.hdfs.server.common.StorageInfo.readProperties(StorageInfo.java:232)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.doTransition(DataStorage.java:759)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.LoadStorageDirectory(DataStorage.java:302)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.LoadDataStorage(DataStorage.java:418)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.addStorageLocations(DataStorage.java:397)
at org.apache.hadoop.hdfs.server.datanode.DataStorage.recoverTransitionRead(DataStorage.java:575)
at org.apache.hadoop.hdfs.server.datanode.DataNode.initStorage(DataNode.java:1560)
at org.apache.hadoop.hdfs.server.datanode.DataNode.initBLockPool(DataNode.java:1520)
at org.apache.hadoop.hdfs.server.datanode.BPOfferService.verifyAndSetNamespaceInfo(BPOfferService.java:341)
at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.connectToNNAndHandshake(BPServiceActor.java:219)
at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:673)
at java.lang.Thread.run(Thread.java:748)
HDFS 2.6.0 DataNode layoutVersion是 -56,HDFS 3.1.1 DataNode layoutVersion是 -57惶我。
DataNode layoutVersion改變的原因:Hadoop社區(qū)自 HDFS-2.8.0 commit HDFS-8791 后妈倔,對DataNode的Layout進(jìn)行了升級,DataNode Block Pool數(shù)據(jù)塊目錄存儲結(jié)構(gòu)從256 x 256個目錄變成了32 x 32個目錄绸贡。目的是通過減少DataNode目錄層級來優(yōu)化Du操作引發(fā)的性能問題盯蝴。
DataNode Layout升級過程:
rename當(dāng)前current目錄,到previous.tmp听怕。
新建current目錄捧挺,并且建立hardlink從previous.tmp到新current目錄。
rename目錄previous.tmp為previous目錄尿瞭。
Layout升級流程圖:
DN Layout升級過程中存儲目錄結(jié)構(gòu):
hardlink的link關(guān)聯(lián)模式圖:
查看DataNodeLayoutVersion代碼闽烙,定義了32 x 32個目錄結(jié)構(gòu)的layoutVersion是-57。說明DataNode Layout升級需要改變layoutVersion声搁。
DataNodeLayoutVersion
public enum Feature implements LayoutFeature {
FIRST_LAYOUT(-55, -53, "First datanode layout", false),
BLOCKID_BASED_LAYOUT(-56,
"The block ID of a finalized block uniquely determines its position " +
"in the directory structure"),
BLOCKID_BASED_LAYOUT_32_by_32(-57,
"Identical to the block id based layout (-56) except it uses a smaller"
+ " directory structure (32x32)");
我們在測試環(huán)境進(jìn)行DataNode Layout升級發(fā)現(xiàn)有如下問題:DataNode創(chuàng)建新的current目錄并建立hardlink的過程非常耗時黑竞,100萬block數(shù)的DataNode從Layout升級開始到對外提供讀寫服務(wù)需要5分鐘。這對于我們接近萬臺DataNode的HDFS集群是不能接受的疏旨,難以在預(yù)定的升級時間窗口內(nèi)完成DataNode 的升級很魂。
因此,我們在HDFS 3.1.1版本回退了 HDFS-8791檐涝,DataNode不進(jìn)行Layout升級遏匆。測試發(fā)現(xiàn)100200萬block數(shù)的DataNode升級只需要90180秒,對比Layout升級時間大幅縮短谁榜。
回退了 HDFS-8791幅聘,DataNode Du帶來的性能問題怎么解決呢?
我們梳理了HDFS 3.3.0版本的patch惰爬,發(fā)現(xiàn)了HDFS-14313 從內(nèi)存中計算DataNode使用空間喊暖,不再使用Du操作, 完美的解決了DataNode Du性能問題撕瞧。我們在升級后的HDFS 3.1.1版本打入HDFS-14313陵叽,解決了DataNode升級后Du操作帶來的io性能問題狞尔。
5.6 DataNode Trash目錄處理
上圖所示,DataNode升級過程中巩掺,DataNode 在刪除 Block 時偏序,是不會真的將 Block 刪除的,而是先將Block 文件放到磁盤BlockPool 目錄下一個 trash 目錄中胖替,為了能夠使用原來的 rollback_fsimage 恢復(fù)升級過程中刪除的數(shù)據(jù)研儒。我們集群磁盤的平均水位一直在80%,本來就很緊張独令,升級期間trash 中的大量Block文件會對集群穩(wěn)定性造成很大威脅端朵。
考慮到我們的方案回退方式是滾動降級而非Rollback,并不會用到trash 中的Block燃箭。所以我們使用腳本定時對 trash 中的 Block 文件進(jìn)行刪除冲呢,這樣可以大大減少 Datanode 上磁盤的存儲壓力。
5.7 其它問題
上述就是我們HDFS升級降級過程中遇到的所有不兼容問題招狸。除了不兼容問題敬拓,我們還在升級的HDP HDFS 3.1.1版本引入了一些NameNode RPC 優(yōu)化patch。
HDFS 2.6.0版本FoldedTreeSet紅黑樹數(shù)據(jù)結(jié)構(gòu)導(dǎo)致NameNode運行一段時間后RPC性能下降裙戏,集群出現(xiàn)大量StaleDataNode乘凸,導(dǎo)致任務(wù)讀取block塊失敗。Hadoop 3.4.0 HDFS-13671 修復(fù)了這個問題累榜,將FoldedTreeSet回退為原來的LightWeightResizableGSet 鏈表數(shù)據(jù)結(jié)構(gòu)营勤。我們也將HDFS-13671 patch引入我們升級的HDP HDFS 3.1.1版本。
升級后HDFS-13671的優(yōu)化效果:集群StaleDataNode數(shù)量大幅減少信柿。
六冀偶、測試與上線
我們在2021年3月份啟動離線數(shù)倉集群HDFS升級專項,在測試環(huán)境搭建了多套HDFS集群進(jìn)行了viewfs模式下多輪HDFS升級渔嚷、降級演練进鸠。不斷的總結(jié)與完善升級方案,解決升級過程中遇到的問題形病。
6.1 全量組件 HDFS 客戶端兼容性測試
在HDFS升級中只升級了Server端客年,HDFS Client還是HDFS 2.6.0版本。因此漠吻,我們要保證業(yè)務(wù)通過HDFS 2.6.0 Client能正常讀寫HDFS 3.1.1集群量瓜。
我們在測試環(huán)境,搭建了線上環(huán)境類似的HDFS測試集群途乃,聯(lián)合計算組同事與業(yè)務(wù)部門绍傲,對Hive、Spark、OLAP(kylin烫饼、presto猎塞、druid)、算法平臺使用HDFS 2.6.0 Client讀寫HDFS 3.1.1杠纵,模擬線上環(huán)境進(jìn)行了全量業(yè)務(wù)的兼容性測試荠耽。確認(rèn)HDFS 2.6.0 Client能正常讀寫HDFS 3.1.1集群,兼容性正常比藻。
6.2 升級操作腳本化
我們嚴(yán)格梳理了HDFS升級降級的命令铝量,梳理了每一步操作的風(fēng)險與注意事項。通過CM银亲、Ambari API啟停HDFS服務(wù)慢叨。將這些操作都整理成python腳本,減少人為操作帶來的風(fēng)險群凶。
6.3 升級點檢
我們梳理了HDFS升級過程中的關(guān)鍵點檢事項插爹,確保HDFS升級過程中出現(xiàn)問題能第一時間發(fā)現(xiàn),進(jìn)行回退请梢,降底對業(yè)務(wù)的影響。
6.4 正式升級
我們在測試環(huán)境中進(jìn)行了多次HDFS升級降級演練力穗,完成HDFS兼容性測試相關(guān)的工作毅弧,公司內(nèi)部寫了多篇WIKI 文檔進(jìn)行記錄。
確認(rèn)測試環(huán)境HDFS升級降級沒問題之后当窗,我們開始了升級之路够坐。
相關(guān)的具體里程碑上線過程如下:
2021年3~4月,梳理HDFS 3.x版本新特性與相關(guān)patch崖面,閱讀HDFS滾動升級降級的源碼元咙,確定最終升級的HDFS 3.x版本。完成HDFS 2.x已有優(yōu)化patch與HDFS 3.x高版本patch移植到升級的HDFS 3.x版本巫员。
2021年5~8月庶香,進(jìn)行HDFS升級降級演練,全量Hive简识、Spark赶掖、OLAP(kylin、presto七扰、druid)兼容性測試奢赂,確定HDFS升級降級方案沒有問題。
2021年9月颈走,yarn日志聚合HDFS集群(百臺)升級到HDP HDFS 3.1.1膳灶,期間修復(fù)日志聚合大量ls調(diào)用導(dǎo)致的RPC性能問題,業(yè)務(wù)未受到影響立由。
2021年11月轧钓,7個離線數(shù)倉HDFS集群(5000臺左右)升級到HDP HDFS 3.1.1序厉,用戶無感知,業(yè)務(wù)未受到影響聋迎。
2022年1月脂矫,完成離線數(shù)倉HDFS集群(10個集群規(guī)模接近萬臺)升級到HDP HDFS 3.1.1,用戶無感知霉晕,業(yè)務(wù)未受到影響庭再。
升級之后,我們對離線數(shù)倉各個集群進(jìn)行了觀察牺堰,目前HDFS服務(wù)運行正常拄轻。
七、總結(jié)
我們耗時一年時間將萬臺規(guī)模的離線數(shù)倉HDFS集群從CDH HDFS 2.6.0升級到了HDP HDFS 3.1.1版本伟葫,管理工具從CM成功切換到了Ambari恨搓。
HDFS 升級過程漫長,但是收益是非常多的筏养,HDFS升級為后續(xù)YARN斧抱、Hive/Spark、HBase組件升級打下了基礎(chǔ)渐溶。
在此基礎(chǔ)上辉浦,我們可以繼續(xù)做非常有意義的工作,持續(xù)在穩(wěn)定性茎辐、性能宪郊、成本等多個方面深入探索,使用技術(shù)為公司創(chuàng)造可見的價值拖陆。
參考資料
- https://issues.apache.org/jira/browse/HDFS-13596
- https://issues.apache.org/jira/browse/HDFS-14396
- https://issues.apache.org/jira/browse/HDFS-14831
- https://issues.apache.org/jira/browse/HDFS-14942
- https://issues.apache.org/jira/browse/HDFS-9788
- https://issues.apache.org/jira/browse/HDFS-3107
- https://issues.apache.org/jira/browse/HDFS-8791
- https://issues.apache.org/jira/browse/HDFS-14313
- https://issues.apache.org/jira/browse/HDFS-13671