架構(gòu)實(shí)戰(zhàn):氣象海量小文件與HDFS優(yōu)化策略)
簡(jiǎn)介一份面向計(jì)算機(jī)科學(xué)與技術(shù)、軟件工程等專(zhuān)業(yè)本科畢業(yè)生的Hadoop方向?qū)W士學(xué)位論文圍繞氣象數(shù)據(jù)的分布式存儲(chǔ)展開(kāi)研究。論文從Hadoop架構(gòu)入手系統(tǒng)講解HDFS分布式文件系統(tǒng)與MapReduce計(jì)算模型并結(jié)合氣溫、濕度、風(fēng)速等多源氣象數(shù)據(jù)的特點(diǎn)設(shè)計(jì)基于Hadoop的存儲(chǔ)系統(tǒng)完整覆蓋系統(tǒng)架構(gòu)、數(shù)據(jù)分布策略、功能實(shí)現(xiàn)與性能評(píng)估。全文按緒論、Hadoop技術(shù)概述、氣象數(shù)據(jù)存儲(chǔ)技術(shù)研究、基于Hadoop的存儲(chǔ)系統(tǒng)設(shè)計(jì)、功能實(shí)現(xiàn)與性能評(píng)估、總結(jié)與展望六章展開(kāi)還包含國(guó)內(nèi)外研究現(xiàn)狀綜述以及數(shù)據(jù)安全、資源管理等實(shí)踐問(wèn)題可作為畢業(yè)論文參考、畢業(yè)設(shè)計(jì)擴(kuò)展或大數(shù)據(jù)入門(mén)學(xué)習(xí)資料。論文為原創(chuàng)撰寫(xiě)未入常見(jiàn)論文庫(kù)可通過(guò)查重系統(tǒng)。資源包為1個(gè)docx文檔壓縮后約31KB已有288人學(xué)習(xí)下載。1. 用Hadoop扛氣象數(shù)據(jù)先想清楚這四件事氣象數(shù)據(jù)是最典型的“海量小文件少量大文件”混合體一個(gè)國(guó)家級(jí)氣象站每分鐘生成的觀測(cè)報(bào)文本只有幾KB一部天氣雷達(dá)一小時(shí)產(chǎn)生的基數(shù)據(jù)卻有幾百M(fèi)B而數(shù)值模式跑一次輸出的格點(diǎn)場(chǎng)動(dòng)輒幾十TB。傳統(tǒng)的NFS集中存儲(chǔ)擴(kuò)不動(dòng)、查不快于是很多人把目光轉(zhuǎn)向基于Hadoop的分布式存儲(chǔ)技術(shù)。但反直覺(jué)的是直接把幾百萬(wàn)個(gè)小文件扔進(jìn)HDFS撐死你的往往不是磁盤(pán)而是NameNode的內(nèi)存——一個(gè)文件元數(shù)據(jù)就要占150字節(jié)左右千萬(wàn)個(gè)文件就是幾個(gè)GB的堆空間。這篇筆記就圍繞這個(gè)矛盾展開(kāi)從氣象數(shù)據(jù)為什么要走Hadoop到偽分布式、HA集群的搭建路線再到小文件合并、跨集群遷移和各類(lèi)翻車(chē)現(xiàn)場(chǎng)的排查方法最后給你一份驗(yàn)證思路和成本測(cè)算。適合氣象業(yè)務(wù)運(yùn)維、數(shù)據(jù)工程崗和做hadoop課程設(shè)計(jì)或研究課題的人新手能跟著敲命令熟手直接看邊界參數(shù)。2. 為什么氣象數(shù)據(jù)必須走分布式存儲(chǔ)從文件體積到計(jì)算模式的硬約束2.1 氣象數(shù)據(jù)的三種典型規(guī)模和訪問(wèn)特征氣象數(shù)據(jù)不是一個(gè)均勻的隊(duì)列至少可以分成三類(lèi)。第一類(lèi)是地面自動(dòng)站觀測(cè)數(shù)據(jù)全國(guó)幾萬(wàn)個(gè)站點(diǎn)逐分鐘上報(bào)單個(gè)文件只有幾KB到幾十KB。這類(lèi)數(shù)據(jù)的特征是“海量、極小、持續(xù)追加”一天下來(lái)可能積累上千萬(wàn)個(gè)文件。它最棘手的問(wèn)題不是容量而是元數(shù)據(jù)數(shù)量——HDFS里每個(gè)文件都對(duì)應(yīng)一串NameNode內(nèi)存中的樹(shù)節(jié)點(diǎn)當(dāng)文件數(shù)突破百萬(wàn)一次啟動(dòng)fsimage加載就會(huì)明顯變慢更不用說(shuō)日常的目錄操作。第二種是氣象雷達(dá)基數(shù)據(jù)一個(gè)體掃文件大約幾十MB到幾百M(fèi)B一天一部雷達(dá)能產(chǎn)生幾個(gè)GB全國(guó)組網(wǎng)就是TB級(jí)。它的訪問(wèn)特征是按站點(diǎn)和時(shí)刻隨機(jī)讀取適合按站點(diǎn)分目錄存儲(chǔ)單個(gè)文件又達(dá)不到HDFS塊大小需要適度合并。第三種是數(shù)值模式輸出的格點(diǎn)場(chǎng)全球模式或區(qū)域模式一次run的產(chǎn)物從幾十GB到幾十TB文件通常是大文件且后續(xù)要做多維切片和統(tǒng)計(jì)分析。它們的共同點(diǎn)是“寫(xiě)一次、讀多次、極少原地修改”這恰好是HDFS的舒適區(qū)。但不同規(guī)模對(duì)塊大小、壓縮格式和副本策略的要求完全不同所以存儲(chǔ)方案必須分層設(shè)計(jì)。我一般先把數(shù)據(jù)按來(lái)源與訪問(wèn)模式分類(lèi)再?zèng)Q定是直接落HDFS、走SequenceFile合并還是轉(zhuǎn)成ORC列式存儲(chǔ)。2.2 HDFS為什么比傳統(tǒng)NAS和對(duì)象存儲(chǔ)更適合氣象數(shù)據(jù)不少人問(wèn)NAS也能擴(kuò)對(duì)象存儲(chǔ)也能存為什么非得用Hadoop這里要從訪問(wèn)模式說(shuō)起。傳統(tǒng)NAS通過(guò)NFS/CIFS掛載適合小規(guī)模共享但元數(shù)據(jù)服務(wù)是中心化的單點(diǎn)文件數(shù)超過(guò)百萬(wàn)后ls都會(huì)卡頓橫向擴(kuò)展要么換代要么加昂貴的專(zhuān)用網(wǎng)關(guān)。對(duì)象存儲(chǔ)比如MinIO、CEPH RGW在容量和帶寬上很強(qiáng)但List操作延遲高、對(duì)大數(shù)據(jù)計(jì)算框架的本地方支持弱Spark/Hive讀對(duì)象存儲(chǔ)往往要走S3A協(xié)議每次讀都要做HTTP握手。放在氣象業(yè)務(wù)的真實(shí)場(chǎng)景里我們經(jīng)常要用MapReduce或Spark直接掃描一個(gè)時(shí)段的全部觀測(cè)文件做質(zhì)控這時(shí)候數(shù)據(jù)本地性Data Locality很關(guān)鍵。HDFS把數(shù)據(jù)切塊分散在各節(jié)點(diǎn)計(jì)算任務(wù)能優(yōu)先調(diào)度到持有數(shù)據(jù)塊的節(jié)點(diǎn)減少網(wǎng)絡(luò)傳輸。這種“存儲(chǔ)與計(jì)算同池”的架構(gòu)讓歷史氣象數(shù)據(jù)回算、批量重處理這類(lèi)任務(wù)的效率比其他方案高一個(gè)量級(jí)。另一層是可靠性三副本機(jī)制或者機(jī)架感知下的雙副本跨機(jī)架副本能夠容忍節(jié)點(diǎn)故障對(duì)長(zhǎng)年累積的氣象歷史數(shù)據(jù)來(lái)說(shuō)硬件損壞是必然的數(shù)據(jù)恢復(fù)能力比鏡像備份更省心。當(dāng)然HDFS不支持原地修改文件如果你要頻繁更新某個(gè)時(shí)次的觀測(cè)值就得走Overwrite重寫(xiě)整個(gè)文件這是選型時(shí)就要接受的限制。為了幫你決策這張表是我常用的對(duì)比維度維度傳統(tǒng)NAS對(duì)象存儲(chǔ)HDFS文件數(shù)上限百萬(wàn)級(jí)后明顯卡頓支持多但List延遲高千萬(wàn)級(jí)需優(yōu)化元數(shù)據(jù)內(nèi)存追加寫(xiě)支持支持只支持塊內(nèi)追加整體重寫(xiě)數(shù)據(jù)本地性無(wú)弱強(qiáng)隨機(jī)讀小文件快一般慢需合并與Spark/Hive集成需掛載通過(guò)S3A有開(kāi)銷(xiāo)原生結(jié)論是如果你的氣象數(shù)據(jù)處理鏈路里只有“存起來(lái)、偶爾下載”對(duì)象存儲(chǔ)夠用一旦要做批量計(jì)算和在線分析基于Hadoop的方案更劃算。這個(gè)判斷也符合當(dāng)前大數(shù)據(jù)平臺(tái)的主流選擇。2.3 存儲(chǔ)格式取舍HDFS塊大小、壓縮、列式存儲(chǔ)確定了用HDFS下一步是定塊大小和文件格式。HDFS默認(rèn)塊大小在舊版本是64MB新版本一般默認(rèn)128MB但氣象數(shù)據(jù)要具體調(diào)。雷達(dá)基數(shù)據(jù)單文件幾百M(fèi)B塊設(shè)成64MB會(huì)讓一個(gè)文件拆成多個(gè)塊讀取時(shí)要跨多個(gè)DataNode如果設(shè)成256MB單體掃描更連續(xù)但也會(huì)減少集群內(nèi)并行度。我一般遵循一個(gè)原則塊大小取“文件平均大小的1~2倍”并且不少于128MB。地面站小文件不能靠調(diào)塊解決必須走合并后面第4章會(huì)展開(kāi)。格式上原始觀測(cè)報(bào)文直接用Text文件存方便氣象業(yè)務(wù)軟件對(duì)接但分析場(chǎng)景要轉(zhuǎn)成列式格式。ORC或Parquet對(duì)浮點(diǎn)格點(diǎn)場(chǎng)的壓縮比很驚人一個(gè)10GB的模式輸出按4字節(jié)浮點(diǎn)存成二進(jìn)制可能是2.5GB用ORC加zlib壓縮后還能再壓到1GB以下。壓縮格式選擇上生產(chǎn)環(huán)境我推薦LZ4或Snappy壓縮速率高解壓帶寬大zstd壓縮比更高但CPU開(kāi)銷(xiāo)也更大。簡(jiǎn)單說(shuō)數(shù)據(jù)沉淀后需要反復(fù)查詢(xún)的轉(zhuǎn)ORC/Gzip只是中間結(jié)果或臨時(shí)數(shù)據(jù)保留Snappy甚至不壓縮。氣象數(shù)據(jù)還有一個(gè)特點(diǎn)時(shí)間維度天然有序按小時(shí)或日期分區(qū)能帶來(lái)顯著的裁剪效果。比如查詢(xún)“2024年5月1日強(qiáng)對(duì)流個(gè)例的雷達(dá)數(shù)據(jù)”分區(qū)裁剪能把掃描范圍從全庫(kù)縮到一個(gè)目錄。所以存儲(chǔ)格式設(shè)計(jì)不是孤立的文件格式問(wèn)題而是“目錄規(guī)劃文件合并列式轉(zhuǎn)換”的組合決策。3. 基于Hadoop的氣象數(shù)據(jù)存儲(chǔ)架構(gòu)從偽分布到HA集群的落地路徑3.1 偽分布式搭建用docker鏡像快速驗(yàn)證存儲(chǔ)方案在正式買(mǎi)服務(wù)器之前先用一臺(tái)機(jī)器或一臺(tái)筆記本上的Docker容器跑通偽分布式是最快的驗(yàn)證方式。網(wǎng)上常見(jiàn)的是hadoop偽分布式搭建教程通常步驟是裝JDK、關(guān)免密登錄、改四個(gè)xml但手動(dòng)配環(huán)境容易翻車(chē)。我習(xí)慣直接拉一個(gè)現(xiàn)成的hadoop docker鏡像比如帶Hadoop 3.x的鏡像用容器起NameNode和DataNode。下面是一組最小命令我用CentOS系統(tǒng)演示但macOS也一樣# 拉取包含 Hadoop 3.3.4 的 Docker 鏡像這里以 bde2020 的鏡像為例 docker pull bde2020/hadoop-base:latest # 用 docker-compose 啟動(dòng)一個(gè)簡(jiǎn)單的集群包含 namenode 和 datanode cat docker-compose.yml EOF version: 3 services: namenode: image: bde2020/hadoop-base:latest container_name: namenode environment: - CORE_CONF_fs_defaultFShdfs://namenode:9000 - HDFS_CONF_dfs_namenode_name_dirfile:///hadoop/dfs/name ports: - 9870:9870 volumes: - ./data:/data command: [hdfs, namenode] datanode: image: bde2020/hadoop-base:latest container_name: datanode environment: - CORE_CONF_fs_defaultFShdfs://namenode:9000 depends_on: - namenode volumes: - ./data/datanode:/hadoop/dfs/data command: [hdfs, datanode] EOF docker-compose up -d這段命令里CORE_CONF_fs_defaultFS 指定了默認(rèn)文件系統(tǒng)的地址偽分布式下所有進(jìn)程都連這一個(gè)NameNode。掛載./data到容器是讓容器退出后數(shù)據(jù)不丟這一步很關(guān)鍵很多新手臨時(shí)起容器關(guān)掉就一切歸零。啟動(dòng)成功后打開(kāi) http://localhost:9870 就能看到NameNode的Web界面Datanode列表里會(huì)出現(xiàn)一個(gè)節(jié)點(diǎn)。然后隨便傳一個(gè)文件測(cè)試# 進(jìn)入容器執(zhí)行 hdfs 命令 docker exec -it namenode bash hdfs dfs -mkdir -p /weather/obs/2024/05 hdfs dfs -put /data/sample_obs.txt /weather/obs/2024/05/ hdfs dfs -ls /weather/obs/2024/05這種方式的優(yōu)點(diǎn)是不污染宿主機(jī)JDK、Hadoop環(huán)境全在鏡像里。缺點(diǎn)是偽分布式只有單機(jī)測(cè)不了機(jī)架感知、故障恢復(fù)這些集群行為。如果你做的是hadoop安裝與配置相關(guān)的課程設(shè)計(jì)或技術(shù)驗(yàn)證偽分布式足夠看到HDFS的完整讀寫(xiě)流程如果要測(cè)HA或擴(kuò)容就得跳到3.2節(jié)的多節(jié)點(diǎn)搭建。另外提醒一句docker鏡像版本魚(yú)龍混雜bde2020這個(gè)系列我看到還在維護(hù)但建議你拉鏡像后先docker inspect看HADOOP_VERSION環(huán)境變量確認(rèn)是3.x再往下走。3.2 多節(jié)點(diǎn)集群搭建NameNode/DataNode/JournalNode部署要點(diǎn)真實(shí)氣象業(yè)務(wù)至少需要三臺(tái)以上物理機(jī)或云主機(jī)。常見(jiàn)做法是部署一個(gè)雙NameNode的HA集群配合3個(gè)JournalNode、3個(gè)ZooKeeper節(jié)點(diǎn)和一組DataNode。下面是我的推薦角色分配以5臺(tái)機(jī)器為例節(jié)點(diǎn)角色node1NameNode(Active)、ZKFC、JournalNodenode2NameNode(Standby)、ZKFC、JournalNodenode3JournalNode、ResourceManager、DataNodenode4DataNode、NodeManagernode5DataNode、NodeManager搭建前要做的準(zhǔn)備所有節(jié)點(diǎn)互信ssh-copy-id、安裝JDK8或JDK11、把Hadoop安裝包解壓到一致路徑。接下來(lái)最核心的是四個(gè)配置文件的修改。先說(shuō)core-site.xmlconfiguration property namefs.defaultFS/name valuehdfs://mycluster/value /property property nameha.zookeeper.quorum/name valuenode1:2181,node2:2181,node3:2181/value /property /configuration這邊f(xié)s.defaultFS不再寫(xiě)成具體namenode地址而是寫(xiě)成邏輯名mycluster由HA服務(wù)去解析當(dāng)前Active節(jié)點(diǎn)。ha.zookeeper.quorum是ZooKeeper連接串用于選舉。然后hdfs-site.xml里要寫(xiě)nameservice、NameNode的RPC地址、故障切換方式configuration property namedfs.nameservices/name valuemycluster/value /property property namedfs.ha.namenodes.mycluster/name valuenn1,nn2/value /property property namedfs.namenode.rpc-address.mycluster.nn1/name valuenode1:8020/value /property property namedfs.namenode.http-address.mycluster.nn1/name valuenode1:9870/value /property property namedfs.namenode.rpc-address.mycluster.nn2/name valuenode2:8020/value /property property namedfs.namenode.http-address.mycluster.nn2/name valuenode2:9870/value /property property namedfs.namenode.shared.edits.dir/name valueqjournal://node1:8485;node2:8485;node3:8485/mycluster/value /property property namedfs.client.failover.proxy.provider.mycluster/name valueorg.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider/value /property property namedfs.ha.automatic-failover.enabled/name valuetrue/value /property /configuration這里最關(guān)鍵的是dfs.namenode.shared.edits.dir它要求所有NameNode把編輯日志寫(xiě)到同一組JournalNode上兩個(gè)NameNode通過(guò)讀取共享日志保持元數(shù)據(jù)同步。自動(dòng)故障轉(zhuǎn)移要靠ZooKeeper所以必須配合3.3節(jié)的ZooKeeper配置。改完配置后不要急著啟動(dòng)所有節(jié)點(diǎn)要按順序先啟動(dòng)ZooKeeper集群再在node1上執(zhí)行hdfs namenode -format然后在node2上執(zhí)行hdfs namenode -bootstrapStandby把元數(shù)據(jù)同步過(guò)來(lái)最后用hdfs haadmin -transitionToActive強(qiáng)制切換一次。這一步容易踩坑后面第5章會(huì)展開(kāi)。3.3 Hadoop與Zookeeper整合實(shí)戰(zhàn)HA高可用的選主與腦裂規(guī)避Hadoop HA能實(shí)現(xiàn)NameNode自動(dòng)切換底層實(shí)際上是ZooKeeper在扛選主。每個(gè)NameNode旁邊跑一個(gè)ZK Failover ControllerZKFC守護(hù)進(jìn)程它負(fù)責(zé)向ZooKeeper登記自己為候選節(jié)點(diǎn)并監(jiān)控NameNode的健康狀態(tài)。當(dāng)Active的ZKFC發(fā)現(xiàn)心跳中斷就自動(dòng)把Active狀態(tài)讓給Standby。這個(gè)過(guò)程就是hadoop和zookeeper整合實(shí)戰(zhàn)中最核心的機(jī)制。ZooKeeper的安裝不需要多講只要保證3個(gè)節(jié)點(diǎn)版本一致。需要注意的是ZooKeeper的myid文件必須唯一conf/zoo.cfg里dataDir要指向有空間的目錄并加上server.1node1:2888:3888這樣的配置。Hadoop這邊需要把ZooKeeper客戶(hù)端相關(guān)JAR放到Hadoop的lib下多數(shù)發(fā)行版已自帶。然后啟動(dòng)順序有講究# 在三臺(tái)ZK節(jié)點(diǎn)上分別啟動(dòng) ZooKeeper zkServer.sh start # 在所有Hadoop節(jié)點(diǎn)啟動(dòng)HDFS start-dfs.sh # 在node1上檢查HA狀態(tài) hdfs haadmin -getAllServiceState # 期望輸出 # node1:8020 active # node2:8020 standby我在實(shí)際部署中遇到最多的問(wèn)題是ZooKeeper起來(lái)了但HDFS的HA沒(méi)有生效NameNode兩側(cè)都顯示standby。原因通常是ZooKeeper會(huì)話(huà)超時(shí)配置太長(zhǎng)或者防火墻沒(méi)放開(kāi)2181、2888端口。建議把dfs.ha.zookeeper.quorum里的地址換成完整主機(jī)名并檢查hosts文件避免不同節(jié)點(diǎn)解析不一致。另一個(gè)坑是腦裂在網(wǎng)絡(luò)分區(qū)時(shí)兩個(gè)NameNode可能同時(shí)認(rèn)為自己是Active。HDFS的解決方案是fencing隔離常見(jiàn)配置是shell指令把對(duì)方殺死或執(zhí)行ssh命令。在hdfs-site.xml里添加property namedfs.ha.fencing.methods/name valuesshfence/value /property property namedfs.ha.fencing.ssh.connect-timeout/name value30000/value /propertysshfence會(huì)在切換前通過(guò)SSH連到舊Active節(jié)點(diǎn)上執(zhí)行fuser -k強(qiáng)制殺掉NameNode進(jìn)程。如果SSH互信沒(méi)配置好fencing會(huì)失敗導(dǎo)致切換不成功這是我在面試時(shí)經(jīng)常用來(lái)梳理的細(xì)節(jié)也提醒你把互信配置到root和hadoop用戶(hù)兩層。4. 氣象數(shù)據(jù)入庫(kù)與訪問(wèn)目錄設(shè)計(jì)、分區(qū)和文件生命周期4.1 目錄與文件命名規(guī)范按觀測(cè)時(shí)間和類(lèi)型組織氣象數(shù)據(jù)一旦進(jìn)入HDFS目錄結(jié)構(gòu)就是它的索引。我在設(shè)計(jì)目錄時(shí)堅(jiān)持三條原則時(shí)間維度獨(dú)立層、數(shù)據(jù)類(lèi)型獨(dú)立層、原始與派生分離。一個(gè)推薦的地面觀測(cè)目錄結(jié)構(gòu)如下/weather/obs/2024/05/01/station_54511_202405010000.txt /weather/radar/2024/05/01/station_Z9000_202405010000.mz /weather/model/global_2024050100/0000/height.grb /weather/derived/2024/05/01/vis_analysis.orc為什么不把時(shí)間放在數(shù)據(jù)站下面比如/weather/station_54511/2024/05/01因?yàn)榻^大多數(shù)氣象查詢(xún)是“某個(gè)時(shí)間段、覆蓋很多站”“按時(shí)間分區(qū)”能讓Spark讀取目錄列表時(shí)直接剪掉無(wú)關(guān)時(shí)間片。文件命名要帶上站號(hào)和觀測(cè)時(shí)刻如station_54511_202405010000.txt這樣即使目錄結(jié)構(gòu)丟了文件名本身還能恢復(fù)元數(shù)據(jù)。原始目錄raw和派生目錄derived分開(kāi)因?yàn)樵紨?shù)據(jù)有氣象業(yè)務(wù)合同要求保留派生數(shù)據(jù)可以隨時(shí)重新生成兩者的生命周期和副本策略可以不同。分區(qū)粒度建議按天。粒度過(guò)細(xì)會(huì)導(dǎo)致目錄數(shù)量爆炸舉例全國(guó)5萬(wàn)站一天一個(gè)文件按小時(shí)分區(qū)就比按天多24倍目錄NameNode的目錄樹(shù)負(fù)擔(dān)很大。只有雷達(dá)數(shù)據(jù)這種單文件大、時(shí)次少的可以按小時(shí)或按時(shí)次分目錄。一旦定了規(guī)范就需要用腳本強(qiáng)制約束我習(xí)慣在采集端就生成符合規(guī)范的路徑入庫(kù)代碼里不再做二次解析減少出錯(cuò)。4.2 小文件合并與SequenceFile/ORC轉(zhuǎn)換大多數(shù)氣象觀測(cè)文件都是小文件如果把原始TXT直接put到HDFS對(duì)NameNode的壓力非常大。解決思路有幾個(gè)一是用Hadoop的CombineFileInputFormat讓計(jì)算框架在讀取時(shí)合并但這對(duì)存儲(chǔ)本身沒(méi)有幫助二是在入庫(kù)前把多個(gè)小文件合并成一個(gè)SequenceFile三是直接轉(zhuǎn)成ORC表。我這里提供一個(gè)用Spark批量轉(zhuǎn)換的思路適合把某一天成千上萬(wàn)個(gè)站的地面觀測(cè)TXT合并成一個(gè)按天分區(qū)的ORC表// 用 Spark 讀取 /weather/obs/2024/05/01 下的所有 txt val inputPath /weather/obs/2024/05/01 val df spark.read .option(delimiter, ,) .option(header, false) .schema(new StructType() .add(station, StringType) .add(time, StringType) .add(temp, DoubleType) .add(pressure, DoubleType)) .csv(inputPath) // 寫(xiě)入 ORC按站號(hào)分區(qū)snappy壓縮 df.write .mode(overwrite) .partitionBy(station) .option(compression, snappy) .orc(/weather/derived/2024/05/01)這段代碼里partitionBy(station) 會(huì)在ORC目錄下再建一層站號(hào)子目錄查詢(xún)單站數(shù)據(jù)時(shí)能快速定位。選擇ORC而不是Parquet是因?yàn)樵贖ive/Spark生態(tài)里ORC的ACID能力和浮點(diǎn)壓縮表現(xiàn)更穩(wěn)定。合并操作完成后原始txt文件是否刪除要視業(yè)務(wù)需要?dú)庀髿v史參考文件一般至少保留一年但可以移到成本更低的目錄比如通過(guò)設(shè)置副本數(shù)為2。如果你不想引入Spark也可以用Hadoop自帶的SequenceFile寫(xiě)入器但維護(hù)一堆byte數(shù)組畢竟麻煩生產(chǎn)上我更愿意定義好Schema后直接上ORC。小文件合并這個(gè)動(dòng)作不只是一次性的我通常會(huì)每天在數(shù)據(jù)接入后觸發(fā)一個(gè)定時(shí)合并任務(wù)比如用Oozie或Airflow調(diào)度避免數(shù)據(jù)文件持續(xù)積壓。4.3 distcp參數(shù)說(shuō)明跨集群遷移與備份氣象數(shù)據(jù)存儲(chǔ)研究里跨集群復(fù)制是常見(jiàn)需求把生產(chǎn)集群的歷史數(shù)據(jù)同步到分析集群做實(shí)驗(yàn)或者做異地災(zāi)備。Hadoop自帶的distcp是首選工具它本質(zhì)上是MapReduce作業(yè)在Map任務(wù)里并行拷貝文件。我最常用的命令是這樣# 把生產(chǎn)集群 /weather 目錄下 2024 年 5 月的數(shù)據(jù)同步到分析集群相同路徑 hadoop distcp -m 20 -b 2048 -p hdfs://prod:8020/weather/obs/2024/05 hdfs://analysis:8020/weather/obs/2024/05參數(shù)說(shuō)明-m 20 表示最多開(kāi)20個(gè)Map任務(wù)并行度過(guò)高會(huì)讓源集群NN壓力大建議根據(jù)源端DataNode數(shù)量設(shè)為節(jié)點(diǎn)數(shù)的1~2倍。-b 2048是帶寬限制單位MB適合在業(yè)務(wù)高峰期做限速避免網(wǎng)卡被打滿(mǎn)。-p保留屬性包括權(quán)限、塊大小、復(fù)制數(shù)等遷移氣象數(shù)據(jù)時(shí)建議保留否則目標(biāo)端副本數(shù)會(huì)使用集群默認(rèn)值。-diff參數(shù)可以增量同步我通常在第二次運(yùn)行時(shí)加上--diff只復(fù)制源與目標(biāo)不同的文件。distcp遇到小文件時(shí)Map任務(wù)還是會(huì)按文件粒度處理所以前面說(shuō)的合并步驟對(duì)distcp同樣能減少任務(wù)數(shù)。還有一個(gè)坑distcp默認(rèn)不會(huì)覆蓋目標(biāo)端同名文件如果業(yè)務(wù)上需要覆蓋請(qǐng)加-overwrite參數(shù)。5. 常見(jiàn)問(wèn)題與避坑排查氣象數(shù)據(jù)存儲(chǔ)翻車(chē)現(xiàn)場(chǎng)5.1 小文件導(dǎo)致NameNode內(nèi)存爆掉現(xiàn)象集群運(yùn)行幾個(gè)月后NameNode的JVM堆內(nèi)存持續(xù)走高頻繁Full GC界面卡死甚至進(jìn)入SafeMode。原因每個(gè)文件元數(shù)據(jù)在NameNode內(nèi)存里大約占150~220字節(jié)含目錄項(xiàng)、權(quán)限、塊信息一堆幾KB的觀測(cè)文件積累到千萬(wàn)級(jí)別堆內(nèi)存幾個(gè)GB就被吃光了。這是“海量小文件分布式存儲(chǔ)”的經(jīng)典組合拳。解決先救命再治本。臨時(shí)調(diào)大NameNode堆內(nèi)存在hadoop-env.sh里設(shè)置HADOOP_NAMENODE_OPTS-Xmx8g并重啟。長(zhǎng)期做法是執(zhí)行4.2的小文件合并把原始TXT按天轉(zhuǎn)成ORC同時(shí)清理無(wú)用的臨時(shí)文件hdfs fsck可用于統(tǒng)計(jì)小文件占比。日常監(jiān)控建議每半小時(shí)記錄一次NN堆內(nèi)存和活躍文件數(shù)閾值設(shè)置到80%時(shí)告警。5.2 塊大小設(shè)成64MB造成大量小塊現(xiàn)象一個(gè)雷達(dá)基數(shù)據(jù)文件300MB讀取時(shí)跨3個(gè)塊花的時(shí)間反而比單塊讀更長(zhǎng)NameNode塊對(duì)象數(shù)量多fsck掃描慢。原因很多教程還是老版本的64MB默認(rèn)值氣象大文件被無(wú)謂切碎。解決在hdfs-site.xml里設(shè)dfs.blocksize為268435456256MB或至少134217728128MB。修改后新寫(xiě)入的文件會(huì)使用新塊大小歷史文件不會(huì)自動(dòng)重切如果需要統(tǒng)一可以用distcp加-updated重寫(xiě)一遍。我一般按數(shù)據(jù)類(lèi)型分別配置比如雷達(dá)目錄用256MB觀測(cè)小文件合并后的ORC塊默認(rèn)128MB即可。5.3 數(shù)據(jù)傾斜與機(jī)架感知配置現(xiàn)象某個(gè)新增DataNode磁盤(pán)利用率很快爆滿(mǎn)而其他節(jié)點(diǎn)空閑或者計(jì)算任務(wù)總是往少數(shù)節(jié)點(diǎn)上跑。原因HDFS數(shù)據(jù)均衡策略是隨機(jī)輪詢(xún)副本放置也沒(méi)有機(jī)架感知集群拓?fù)浔划?dāng)作單機(jī)架處理。解決配置機(jī)架感知腳本讓Hadoop知道網(wǎng)絡(luò)拓?fù)?。在core-site.xml里設(shè)置property namenet.topology.script.file.name/name value/opt/hadoop/etc/hadoop/rack-aware.sh/value /property腳本內(nèi)容按IP映射到機(jī)架名例如#!/bin/bash # 簡(jiǎn)單的機(jī)架感知腳本前兩個(gè)字節(jié)相同視為同一機(jī)架 case $1 in 192.168.1.*) echo /rack-1 ;; 192.168.2.*) echo /rack-2 ;; *) echo /rack-default ;; esac注意腳本要有可執(zhí)行權(quán)限。有了機(jī)架感知HDFS在第二個(gè)副本時(shí)會(huì)優(yōu)先放到不同機(jī)架第三個(gè)副本再回到第一個(gè)副本所在機(jī)架的不同節(jié)點(diǎn)這樣既容災(zāi)又均衡。如果已經(jīng)存在傾斜執(zhí)行hdfs balancer -threshold 10讓它均衡但要在業(yè)務(wù)低峰跑因?yàn)樗鼤?huì)占用IO。5.4 副本策略在氣象場(chǎng)景下的調(diào)整現(xiàn)象默認(rèn)3副本磁盤(pán)成本翻三倍氣象原始數(shù)據(jù)有壓縮歸檔卻沒(méi)地方放。原因很多人照搬默認(rèn)配置沒(méi)想過(guò)氣象數(shù)據(jù)的副本需求其實(shí)可以從3降到2甚至1。解決氣象數(shù)據(jù)有重建途徑如雷達(dá)基數(shù)據(jù)可以從雷達(dá)站重新導(dǎo)模式數(shù)據(jù)可以重新run對(duì)原始觀測(cè)文件2副本已經(jīng)能容忍單節(jié)點(diǎn)故障如果有Hadoop Archive冷備份副本可降到1。設(shè)置方式在hdfs-site.xml里全局改dfs.replication2也可以對(duì)特定目錄設(shè)置hdfs dfs -setrep -R 2 /weather/raw這個(gè)命令會(huì)把指定目錄及已有文件的副本數(shù)改成2適合對(duì)不同數(shù)據(jù)類(lèi)型做差異化成本控制。不過(guò)要提醒副本數(shù)設(shè)得太低在DataNode單點(diǎn)故障時(shí)會(huì)導(dǎo)致塊丟失需要用hdfs fsck -list-corruptfileblocks定期檢查。降副本前務(wù)必確認(rèn)數(shù)據(jù)源還有原始文件否則一旦磁盤(pán)壞就是真翻車(chē)。5.5 磁盤(pán)故障與節(jié)點(diǎn)掉線后的恢復(fù)時(shí)序現(xiàn)象DataNode進(jìn)程在但Web UI顯示某個(gè)塊副本缺失或者某塊磁盤(pán)IO錯(cuò)誤節(jié)點(diǎn)被標(biāo)記為壞盤(pán)最終Node進(jìn)入Decommission狀態(tài)。原因DataNode多目錄中一個(gè)壞盤(pán)會(huì)導(dǎo)致整個(gè)節(jié)點(diǎn)被判斷為異常NameNode檢測(cè)到超時(shí)后啟動(dòng)塊復(fù)制但因?yàn)楦北旧倩蚓W(wǎng)絡(luò)帶寬不夠恢復(fù)很慢。解決該節(jié)點(diǎn)的hdfs-site.xml里設(shè)置dfs.datanode.data.dir為多個(gè)獨(dú)立盤(pán)目錄例如/srv/hdfs/data1,/srv/hdfs/data2這樣單盤(pán)損壞只影響那部分塊不會(huì)整個(gè)節(jié)點(diǎn)宕掉。壞盤(pán)處理流程是發(fā)現(xiàn)壞盤(pán) → 從配置中移除該目錄 → 修改fsimage并重啟DataNode → 等待塊的re-replicate?;謴?fù)期間可以用hdfs dfsadmin -report查看各節(jié)點(diǎn)磁盤(pán)狀態(tài)用hdfs fsck /weather -files -blocks檢查損壞文件列表。再一個(gè)常見(jiàn)坑很多人在DataNode內(nèi)存溢出或磁盤(pán)滿(mǎn)后不檢查就重啟導(dǎo)致節(jié)點(diǎn)反復(fù)異常。應(yīng)該先看日志/opt/hadoop/logs/hadoop-hdfs-datanode-*.log里的異常再動(dòng)手。6. 這個(gè)方案值不值得投入驗(yàn)證方法、成本估算與一個(gè)進(jìn)階技巧6.1 用hadoop面試題清單給存儲(chǔ)方案做驗(yàn)證做完這套架構(gòu)你可以用幾個(gè)hadoop面試題來(lái)驗(yàn)收自己是否真正吃透請(qǐng)描述NameNode的啟動(dòng)流程以及SecondaryNameNode與HA中的Standby節(jié)點(diǎn)有什么區(qū)別。副本放置策略的默認(rèn)規(guī)則是什么機(jī)架感知改了之后會(huì)影響哪些行為小文件為什么影響HDFS除了合并還有哪些治理手段distcp在增量同步時(shí)如何保證數(shù)據(jù)一致性這些問(wèn)題覆蓋了從原理到運(yùn)維的邊界。如果你能不看文檔答上來(lái)說(shuō)明你的氣象數(shù)據(jù)存儲(chǔ)方案不是搭個(gè)環(huán)境了事。我自己的習(xí)慣是每完成一個(gè)集群節(jié)點(diǎn)配置就在心里過(guò)一遍這些題用來(lái)發(fā)現(xiàn)盲區(qū)比如最初我以為Standby節(jié)點(diǎn)就是用來(lái)讀的實(shí)際上它的主要職責(zé)是熱備和及時(shí)切換。6.2 存儲(chǔ)成本與壓縮比實(shí)測(cè)方法在投入生產(chǎn)前建議先搞一個(gè)真實(shí)月份的樣本測(cè)試。選擇最近一個(gè)完整月的數(shù)據(jù)統(tǒng)計(jì)原始大小、文件個(gè)數(shù)。然后用下面的命令測(cè)量HDFS實(shí)際占用# 查看某個(gè)目錄的實(shí)際容量-h 顯示人類(lèi)可讀 hdfs dfs -du -h /weather/raw/2024/05假設(shè)原始數(shù)據(jù)是2TBHDFS占用為2TB × 副本數(shù)2 4TB如果轉(zhuǎn)成ORC壓縮后體積變?yōu)?00GB那么有效存儲(chǔ)成本就變成4TB里實(shí)際只用了600GB的物理空間緊縮比約70%。再結(jié)合硬盤(pán)價(jià)格和服務(wù)器折舊就能算出每TB氣象數(shù)據(jù)成本。這里要注意du顯示的是邏輯塊大小不是物理磁盤(pán)寫(xiě)入量因?yàn)閴K校驗(yàn)checksum也會(huì)占用一點(diǎn)點(diǎn)空間但通常忽略。還要算上NameNode內(nèi)存成本每100萬(wàn)文件大約需要200MB堆內(nèi)存按云主機(jī)單價(jià)折算也是一筆賬。把這些算完你就可以給決策層交一份有數(shù)字的存儲(chǔ)預(yù)算方案。6.3 一個(gè)進(jìn)階技巧基于文件大小的自動(dòng)歸檔策略最后給你一個(gè)實(shí)用的冷熱分層技巧。氣象歷史數(shù)據(jù)訪問(wèn)頻率越來(lái)越低但磁盤(pán)還在持續(xù)寫(xiě)入??梢杂肏adoop ArchiveHAR歸檔老數(shù)據(jù)將多個(gè)小文件打包成har文件減少NameNode元數(shù)據(jù)壓力同時(shí)不丟數(shù)據(jù)。建一個(gè)定時(shí)歸檔任務(wù)# 把 2023 年及以前的觀測(cè)原始文件歸檔成 har 包 hadoop archive -archiveName obs-2023.har -p /weather/obs/2023 /weather/archive/2023執(zhí)行后/weather/archive/2023下會(huì)出現(xiàn)一個(gè)obs-2023.har里面包含所有小文件。訪問(wèn)歸檔文件時(shí)不用解壓可以直接hdfs dfs -ls har:///weather/archive/2023/obs-2023.har讀取。歸檔后原始目錄可以設(shè)置成只讀或清理你仍然能通過(guò)Spark讀har里的數(shù)據(jù)只是性能略低于未歸檔。這個(gè)技巧特別適合存量氣候數(shù)據(jù)能在一周內(nèi)存活集群的元數(shù)據(jù)壓力降一個(gè)量級(jí)。我的教訓(xùn)是歸檔腳本要放在業(yè)務(wù)低峰執(zhí)行并且先跑一次小范圍樣例驗(yàn)證查詢(xún)端能正常讀har再全量歸檔因?yàn)镠AR壓縮過(guò)程如果中途失敗部分小文件可能不可見(jiàn)需要原始目錄的副本兜底。這套基于Hadoop的氣象數(shù)據(jù)分布式存儲(chǔ)方案從架構(gòu)選型到集群搭建、數(shù)據(jù)入庫(kù)、成本測(cè)算我已經(jīng)講完了。如果你正在做氣象數(shù)據(jù)平臺(tái)建議先從偽分布式驗(yàn)證目錄設(shè)計(jì)和合并流程再逐步擴(kuò)展到HA集群。每個(gè)環(huán)節(jié)的數(shù)據(jù)格式、塊大小、副本策略都要結(jié)合你自己的數(shù)據(jù)規(guī)模去試不要照抄默認(rèn)值。單機(jī)實(shí)驗(yàn)和集群生產(chǎn)之間最大的差別往往就在那些看起來(lái)不起眼的參數(shù)上等你因?yàn)橐粋€(gè)配置失誤半夜爬起來(lái)重啟節(jié)點(diǎn)時(shí)就會(huì)懂我今天為什么把這些坑單列一章。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取