大數(shù)據(jù)平臺(tái)搭建實(shí)戰(zhàn):從選型到避坑)
簡(jiǎn)介這是一份面向計(jì)算機(jī)科學(xué)與技術(shù)、軟件工程等專(zhuān)業(yè)本科及專(zhuān)科畢業(yè)生的原創(chuàng)學(xué)士學(xué)位論文主題為基于Hadoop的鐵路貨運(yùn)大數(shù)據(jù)平臺(tái)設(shè)計(jì)與應(yīng)用適合需要完成畢業(yè)論文或研究大數(shù)據(jù)處理與分布式計(jì)算的學(xué)習(xí)者參考。論文圍繞HDFS分布式存儲(chǔ)、MapReduce編程模型、鐵路貨運(yùn)數(shù)據(jù)特點(diǎn)、平臺(tái)總體架構(gòu)與功能模塊設(shè)計(jì)、應(yīng)用案例及安全性與優(yōu)化策略展開(kāi)采用文獻(xiàn)綜述、理論分析與實(shí)證研究相結(jié)合的方法并強(qiáng)調(diào)未入庫(kù)、可通過(guò)查重系統(tǒng)。資源包共1個(gè)docx文件約35KB內(nèi)容為完整論文正文目錄結(jié)構(gòu)清晰涵蓋緒論、Hadoop技術(shù)基礎(chǔ)、數(shù)據(jù)特點(diǎn)分析、平臺(tái)設(shè)計(jì)與應(yīng)用案例等章節(jié)。目前已有192人學(xué)習(xí)讀者可借此掌握Hadoop核心概念與工作原理理解其在貨運(yùn)調(diào)度、監(jiān)控和決策支持中的實(shí)際應(yīng)用并獲得可參考的論文寫(xiě)作框架與部署優(yōu)化思路。1. 鐵路貨運(yùn)數(shù)據(jù)堆到 PB 級(jí)之后為什么單機(jī) MySQL 一定會(huì)先崩車(chē)務(wù)段的朋友半夜打電話(huà)過(guò)來(lái)說(shuō)他們那個(gè)跑了三年的貨運(yùn)統(tǒng)計(jì)庫(kù)又鎖死了。我遠(yuǎn)程連上去一看一張waybill_detail表 4.2 億行一個(gè)不帶索引的GROUP BY把 InnoDB 的 buffer pool 沖得干干凈凈。這不是個(gè)例鐵路貨運(yùn)的數(shù)據(jù)形態(tài)天生就是給單機(jī)數(shù)據(jù)庫(kù)上刑的一趟中歐班列從裝車(chē)到口岸換裝沿途要產(chǎn)生車(chē)號(hào)識(shí)別、超偏載檢測(cè)、集裝箱定位、貨票報(bào)文、裝卸作業(yè)記錄等十幾類(lèi)數(shù)據(jù)單列車(chē)的軌跡點(diǎn)就能到幾十萬(wàn)條一個(gè)路局一年下來(lái)輕松過(guò) TB。標(biāo)題里說(shuō)的「基于 Hadoop 的鐵路貨運(yùn)大數(shù)據(jù)平臺(tái)」本質(zhì)上就是解決這個(gè)量級(jí)下的存儲(chǔ)和計(jì)算問(wèn)題。它適合兩類(lèi)人一類(lèi)是路局或物流企業(yè)的數(shù)據(jù)開(kāi)發(fā)手里有貨票、車(chē)號(hào)、GPS 軌跡數(shù)據(jù)但被單機(jī)庫(kù)卡住另一類(lèi)是想拿一個(gè)真實(shí)行業(yè)場(chǎng)景練 Hadoop 全棧的工程師鐵路貨運(yùn)的數(shù)據(jù)模型比電商訂單更有意思因?yàn)樗臅r(shí)空關(guān)聯(lián)性極強(qiáng)。這篇筆記我按自己搭過(guò)的一套最小可用平臺(tái)來(lái)講從選型到跑通再到踩坑能抄的地方直接給命令和配置。2. 平臺(tái)分層怎么切從貨票報(bào)文到指標(biāo)看板的五層鏈路2.1 為什么是 HDFS 加 YARN 加 Hive 這套組合而不是換一個(gè)更大的 Oracle先說(shuō)選型理由不然后面搭起來(lái)心里沒(méi)底。鐵路貨運(yùn)數(shù)據(jù)的核心特征是「寫(xiě)多讀少、批量分析為主、歷史數(shù)據(jù)不能刪」。貨票報(bào)文一旦入庫(kù)基本只做歸檔和統(tǒng)計(jì)不會(huì)頻繁更新超偏載檢測(cè)數(shù)據(jù)是典型的時(shí)序追加集裝箱軌跡是高頻點(diǎn)位寫(xiě)入。這三種負(fù)載用 Oracle RAC 硬扛成本曲線(xiàn)是線(xiàn)性的數(shù)據(jù)翻倍機(jī)器就得翻倍。Hadoop 這套的價(jià)值在于存儲(chǔ)和計(jì)算解耦。HDFS 用三副本保證貨票數(shù)據(jù)不丟NameNode 管元數(shù)據(jù)DataNode 管塊存儲(chǔ)加機(jī)器就是加 DataNode容量和吞吐一起漲。YARN 把計(jì)算資源池化白天跑報(bào)表、晚上跑全量對(duì)賬同一批機(jī)器分時(shí)復(fù)用。Hive 把 HDFS 上的文件映射成表讓會(huì)寫(xiě) SQL 的貨運(yùn)業(yè)務(wù)人員也能查數(shù)據(jù)不用每個(gè)人都去寫(xiě) MapReduce。常見(jiàn)做法是五層采集層用 Flume 或 DataX 把貨票系統(tǒng)和車(chē)號(hào)識(shí)別系統(tǒng)的數(shù)據(jù)抽過(guò)來(lái)存儲(chǔ)層 HDFS 做原始區(qū)Hive 做數(shù)倉(cāng)分層計(jì)算層 YARN 調(diào)度 MapReduce 和 Spark服務(wù)層用 HiveServer2 或 Presto 對(duì)外提供查詢(xún)應(yīng)用層接 BI 看板和調(diào)度系統(tǒng)。這套分層不是照搬教科書(shū)是鐵路場(chǎng)景下數(shù)據(jù)流向決定的——原始報(bào)文必須留底所以 ODS 層不能省。2.2 偽分布式先跑通再上三節(jié)點(diǎn)集群新手最容易翻車(chē)的地方是一上來(lái)就搭五節(jié)點(diǎn) HA 集群結(jié)果 NameNode 格式化三次都沒(méi)成功。我的建議是先用偽分布式把 Hive 建表查數(shù)跑通再擴(kuò)集群。下面是 Ubuntu 下偽分布式的核心配置JDK 用 8Hadoop 用 3.x 系列。# 1. 配置 SSH 免密偽分布式也需要 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys # 2. 解壓并配置環(huán)境變量 tar -xzvf hadoop-3.x.tar.gz -C /opt/ echo export HADOOP_HOME/opt/hadoop ~/.bashrc echo export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin ~/.bashrc source ~/.bashrc這段腳本做兩件事免密登錄是 Hadoop 腳本內(nèi)部用 ssh 拉起進(jìn)程的前提環(huán)境變量決定hdfs、yarn這些命令能不能直接敲。參數(shù)上注意-P 表示空密碼生產(chǎn)環(huán)境不要這么干但本地偽分布式無(wú)所謂。接下來(lái)改core-site.xml和hdfs-site.xml!-- core-site.xml指定 NameNode 地址和臨時(shí)目錄 -- configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/opt/hadoop/data/tmp/value /property /configuration !-- hdfs-site.xml偽分布式副本數(shù)必須為 1 -- configuration property namedfs.replication/name value1/value /property property namedfs.namenode.name.dir/name value/opt/hadoop/data/namenode/value /property property namedfs.datanode.data.dir/name value/opt/hadoop/data/datanode/value /property /configurationfs.defaultFS里的 9000 是 NameNode 的 RPC 端口后面 Hive 連 HDFS 就靠這個(gè)地址。dfs.replication設(shè) 1 是因?yàn)閭畏植际街挥幸粋€(gè) DataNode設(shè) 3 會(huì)一直報(bào)副本不足的警告。hadoop.tmp.dir一定要顯式指定默認(rèn)在/tmp下機(jī)器重啟數(shù)據(jù)就沒(méi)了這是血淚經(jīng)驗(yàn)。格式化并啟動(dòng)hdfs namenode -format start-dfs.sh start-yarn.sh jps # 應(yīng)該看到 NameNode、DataNode、ResourceManager、NodeManagerjps是排查啟動(dòng)問(wèn)題最直接的工具少哪個(gè)進(jìn)程就去翻對(duì)應(yīng)的日志日志在$HADOOP_HOME/logs下。NameNode 沒(méi)起來(lái)通常是hadoop.tmp.dir權(quán)限問(wèn)題或者之前格式化殘留刪掉 data 目錄重新格式化即可。2.3 Hive 建貨運(yùn)數(shù)倉(cāng)ODS 到 DWD 的字段設(shè)計(jì)Hive 建表是鐵路貨運(yùn)平臺(tái)的核心工作。我一般分三層ODS 存原始貨票報(bào)文DWD 做清洗后的明細(xì)DWS 做聚合寬表。先看 ODS 層建表-- ODS原始貨票報(bào)文按天分區(qū) CREATE EXTERNAL TABLE ods_waybill ( waybill_no STRING COMMENT 貨票號(hào), train_no STRING COMMENT 車(chē)次, send_station STRING COMMENT 發(fā)站, recv_station STRING COMMENT 到站, cargo_type STRING COMMENT 貨物品類(lèi), weight_ton DOUBLE COMMENT 計(jì)費(fèi)重量噸, wagon_no STRING COMMENT 車(chē)號(hào), report_time STRING COMMENT 報(bào)文時(shí)間 ) COMMENT 貨票原始報(bào)文 PARTITIONED BY (dt STRING COMMENT 日期分區(qū)) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t STORED AS TEXTFILE LOCATION /warehouse/ods/waybill;用 EXTERNAL 表是因?yàn)樵紨?shù)據(jù)不能丟刪表只刪元數(shù)據(jù)不刪 HDFS 文件。分區(qū)字段dt按天切鐵路貨運(yùn)查詢(xún)幾乎都帶時(shí)間范圍分區(qū)裁剪能把掃描量降一個(gè)數(shù)量級(jí)。分隔符用\t是因?yàn)樨浧毕到y(tǒng)導(dǎo)出的文本默認(rèn)制表符分隔如果源數(shù)據(jù)是逗號(hào)分隔就改成,但要注意貨物品類(lèi)里可能含逗號(hào)這種情況得先做轉(zhuǎn)義。DWD 層做清洗重點(diǎn)處理車(chē)號(hào)補(bǔ)零和站點(diǎn)名稱(chēng)標(biāo)準(zhǔn)化-- DWD清洗后明細(xì)車(chē)號(hào)統(tǒng)一 7 位站點(diǎn)去空格 CREATE TABLE dwd_waybill_detail ( waybill_no STRING, train_no STRING, send_station STRING, recv_station STRING, cargo_type STRING, weight_ton DOUBLE, wagon_no STRING, report_time TIMESTAMP ) PARTITIONED BY (dt STRING) STORED AS ORC; -- 清洗邏輯車(chē)號(hào)左側(cè)補(bǔ)零到 7 位站點(diǎn)去空格 INSERT OVERWRITE TABLE dwd_waybill_detail PARTITION (dt2024-01-01) SELECT waybill_no, train_no, trim(send_station), trim(recv_station), cargo_type, weight_ton, lpad(wagon_no, 7, 0), from_unixtime(unix_timestamp(report_time, yyyyMMddHHmmss)) FROM ods_waybill WHERE dt 2024-01-01 AND waybill_no IS NOT NULL;lpad補(bǔ)零是鐵路車(chē)號(hào)的硬性要求車(chē)號(hào)識(shí)別系統(tǒng)出來(lái)的數(shù)據(jù)經(jīng)常丟前導(dǎo)零不補(bǔ)的話(huà)關(guān)聯(lián)車(chē)輛臺(tái)賬會(huì)對(duì)不上。from_unixtime把報(bào)文里的字符串時(shí)間轉(zhuǎn)成標(biāo)準(zhǔn) TIMESTAMP方便后面做時(shí)間窗口聚合。ORC 格式比 TEXTFILE 省一半以上存儲(chǔ)查詢(xún)也快DWD 層開(kāi)始就該用列式存儲(chǔ)。3. 把貨票和軌跡關(guān)聯(lián)起來(lái)MapReduce 還是 Spark SQL3.1 什么時(shí)候必須寫(xiě) MapReduce什么時(shí)候 Hive SQL 就夠了鐵路貨運(yùn)平臺(tái)里 80% 的統(tǒng)計(jì)需求 Hive SQL 能搞定比如按品類(lèi)統(tǒng)計(jì)發(fā)送量、按站點(diǎn)統(tǒng)計(jì)到達(dá)量。但有兩類(lèi)場(chǎng)景繞不開(kāi)手寫(xiě)代碼一是貨票數(shù)據(jù)和車(chē)號(hào)識(shí)別數(shù)據(jù)做關(guān)聯(lián)時(shí)兩邊的時(shí)間戳格式不一致需要自定義解析邏輯二是集裝箱軌跡的去重和停留點(diǎn)識(shí)別涉及狀態(tài)機(jī)判斷SQL 表達(dá)起來(lái)很別扭。我一般的原則是能用 SQL 解決的絕不寫(xiě) MapReduce因?yàn)?MapReduce 的開(kāi)發(fā)和調(diào)試成本太高一個(gè) join 寫(xiě)錯(cuò)方向就要重跑半小時(shí)。但涉及復(fù)雜事件處理比如判斷一趟班列在某個(gè)編組站是否發(fā)生了二次編組這種邏輯用 Spark 的mapPartitions比 SQL 清晰得多。3.2 一個(gè)貨票與軌跡關(guān)聯(lián)的 MapReduce 作業(yè)骨架下面是一個(gè)典型的 reduce-side join把貨票明細(xì)和車(chē)號(hào)識(shí)別記錄按車(chē)號(hào)關(guān)聯(lián)輸出每輛車(chē)的實(shí)際運(yùn)行路徑。Mapper 階段給兩個(gè)數(shù)據(jù)源打標(biāo)簽// Mapper貨票數(shù)據(jù)打 tag0軌跡數(shù)據(jù)打 tag1 public class WaybillJoinMapper extends MapperLongWritable, Text, Text, Text { Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line value.toString(); String[] fields line.split(\t); // 根據(jù)字段數(shù)量或來(lái)源目錄判斷數(shù)據(jù)類(lèi)型 if (fields.length 8) { // 貨票車(chē)號(hào)作為 keytag0 標(biāo)記 context.write(new Text(fields[6]), new Text(0\t line)); } else if (fields.length 4) { // 軌跡車(chē)號(hào)作為 keytag1 標(biāo)記 context.write(new Text(fields[0]), new Text(1\t line)); } } }Reducer 階段把同一個(gè)車(chē)號(hào)的兩類(lèi)數(shù)據(jù)分開(kāi)緩存然后做笛卡爾關(guān)聯(lián)// Reducer同一車(chē)號(hào)的貨票和軌跡做關(guān)聯(lián) public class WaybillJoinReducer extends ReducerText, Text, Text, Text { Override protected void reduce(Text key, IterableText values, Context context) throws IOException, InterruptedException { ListString waybills new ArrayList(); ListString tracks new ArrayList(); for (Text val : values) { String[] parts val.toString().split(\t, 2); if (0.equals(parts[0])) { waybills.add(parts[1]); } else { tracks.add(parts[1]); } } // 關(guān)聯(lián)輸出貨票號(hào) 軌跡點(diǎn) for (String wb : waybills) { String waybillNo wb.split(\t)[0]; for (String tk : tracks) { context.write(new Text(waybillNo), new Text(tk)); } } } }這段代碼的關(guān)鍵在split(\t, 2)的第二個(gè)參數(shù)限制分割次數(shù)為 2保證原始行里的制表符不會(huì)被切碎。實(shí)際生產(chǎn)中如果軌跡數(shù)據(jù)量遠(yuǎn)大于貨票要做 map-side join把小表貨票加載到 DistributedCache 里避免 reduce 端數(shù)據(jù)傾斜。鐵路場(chǎng)景下車(chē)號(hào)分布相對(duì)均勻傾斜不嚴(yán)重但春運(yùn)期間某些熱門(mén)線(xiàn)路的車(chē)號(hào)會(huì)集中這時(shí)候需要加隨機(jī)前綴打散。3.3 用 Spark SQL 做停留點(diǎn)識(shí)別窗口函數(shù)比自連接快在哪集裝箱在編組站的停留時(shí)間分析是鐵路貨運(yùn)的剛需指標(biāo)。傳統(tǒng)寫(xiě)法是自連接找相鄰兩條軌跡記錄數(shù)據(jù)量一大就 O(n2)。用 Spark SQL 的窗口函數(shù)可以一趟掃完-- 用 lag 窗口函數(shù)計(jì)算相鄰軌跡點(diǎn)的時(shí)間差 WITH track_with_lag AS ( SELECT container_no, station_code, event_time, LAG(event_time) OVER (PARTITION BY container_no ORDER BY event_time) AS prev_time, LAG(station_code) OVER (PARTITION BY container_no ORDER BY event_time) AS prev_station FROM dwd_container_track WHERE dt BETWEEN 2024-01-01 AND 2024-01-31 ) SELECT container_no, prev_station AS station_code, prev_time AS arrive_time, event_time AS depart_time, (unix_timestamp(event_time) - unix_timestamp(prev_time)) / 3600.0 AS stay_hours FROM track_with_lag WHERE prev_station station_code AND (unix_timestamp(event_time) - unix_timestamp(prev_time)) 7200 ORDER BY stay_hours DESC;LAG函數(shù)把上一行的時(shí)間拉過(guò)來(lái)PARTITION BY container_no保證按集裝箱分組ORDER BY event_time保證時(shí)間有序。prev_station station_code篩出同一站點(diǎn)的連續(xù)記錄時(shí)間差大于 7200 秒2 小時(shí)才算停留。這個(gè)寫(xiě)法比自連接少一次全表掃描在千萬(wàn)級(jí)軌跡數(shù)據(jù)上差距很明顯。參數(shù)上注意unix_timestamp返回秒除以 3600 轉(zhuǎn)小時(shí)如果數(shù)據(jù)里有跨天的情況要確認(rèn)時(shí)區(qū)配置。4. 避坑與排查鐵路貨運(yùn)平臺(tái)搭建中最容易翻車(chē)的五件事4.1 DataNode 磁盤(pán)寫(xiě)滿(mǎn)導(dǎo)致整個(gè)集群假死現(xiàn)象Hive 查詢(xún)突然全部卡住jps看進(jìn)程都在但hdfs dfsadmin -report顯示某些 DataNode 的剩余空間為 0。原因是鐵路貨運(yùn)數(shù)據(jù)只增不減ODS 層沒(méi)設(shè) TTL半年就把磁盤(pán)吃滿(mǎn)。DataNode 寫(xiě)滿(mǎn)后不會(huì)自動(dòng)退出但會(huì)拒絕寫(xiě)入NameNode 還在往它上面分配塊導(dǎo)致寫(xiě)入超時(shí)。解決給 ODS 層加生命周期管理用hdfs dfs -setStoragePolicy設(shè)置冷數(shù)據(jù)歸檔或者直接在 Hive 里按分區(qū)刪除超過(guò)一年的數(shù)據(jù)。更穩(wěn)妥的做法是配dfs.datanode.du.reserved預(yù)留 10% 磁盤(pán)空間給系統(tǒng)留緩沖。4.2 小文件過(guò)多把 NameNode 內(nèi)存撐爆現(xiàn)象NameNode 頻繁 Full GCjstat看老年代一直滿(mǎn)集群響應(yīng)變慢。原因是 Flume 按小時(shí)滾動(dòng)文件每個(gè)文件只有幾十 KB一年下來(lái)幾百萬(wàn)個(gè)小文件每個(gè)文件在 NameNode 里占約 150 字節(jié)元數(shù)據(jù)幾百萬(wàn)個(gè)就是幾百 MB 堆內(nèi)存。解決用 Hive 的concatenate命令合并 ORC 小文件或者在 ETL 階段加一步INSERT OVERWRITE重寫(xiě)分區(qū)。更根本的辦法是調(diào) Flume 的rollInterval和rollSize讓文件至少到 128MB 再滾動(dòng)。鐵路貨運(yùn)的報(bào)文數(shù)據(jù)單條不大但積少成多這個(gè)坑幾乎每個(gè)平臺(tái)都會(huì)踩。4.3 Hive 動(dòng)態(tài)分區(qū)把內(nèi)存寫(xiě)爆現(xiàn)象跑一個(gè)帶動(dòng)態(tài)分區(qū)的 INSERT 語(yǔ)句報(bào)GC overhead limit exceeded。原因是動(dòng)態(tài)分區(qū)默認(rèn)每個(gè)分區(qū)至少 100MB 才切換但鐵路貨運(yùn)按站點(diǎn)分區(qū)時(shí)很多小站一天只有幾條數(shù)據(jù)導(dǎo)致同時(shí)打開(kāi)幾千個(gè)分區(qū)寫(xiě)句柄。解決設(shè)置hive.exec.dynamic.partition.modenonstrict允許全動(dòng)態(tài)分區(qū)同時(shí)調(diào)小hive.exec.max.dynamic.partitions.pernode或者改用按天分區(qū)、站點(diǎn)作為普通字段。我一般建議鐵路場(chǎng)景按天分區(qū)就夠了站點(diǎn)維度用索引或分桶解決。4.4 車(chē)號(hào)關(guān)聯(lián)時(shí)數(shù)據(jù)傾斜拖慢整個(gè)作業(yè)現(xiàn)象MapReduce 作業(yè)跑到 99% 卡住看 Counter 發(fā)現(xiàn)某個(gè) reduce 處理的數(shù)據(jù)量是其他的幾十倍。原因是某些測(cè)試車(chē)號(hào)或默認(rèn)車(chē)號(hào)比如全零在數(shù)據(jù)里出現(xiàn)頻率極高這些異常值全被分到同一個(gè) reduce。解決在 Mapper 階段過(guò)濾掉明顯異常的車(chē)號(hào)或者給高頻 key 加隨機(jī)后綴打散Reducer 里再做二次聚合。鐵路數(shù)據(jù)里0000000這種車(chē)號(hào)通常是識(shí)別失敗占位符直接過(guò)濾掉最省事。4.5 YARN 隊(duì)列資源被一個(gè)作業(yè)獨(dú)占現(xiàn)象提交一個(gè) Spark 作業(yè)后其他所有作業(yè)都排隊(duì)等資源。原因是沒(méi)配 Capacity Scheduler 的隊(duì)列上限默認(rèn)隊(duì)列允許單作業(yè)占用 100% 資源。鐵路貨運(yùn)平臺(tái)通常白天要跑實(shí)時(shí)報(bào)表晚上跑批量對(duì)賬不隔離的話(huà)互相影響。解決在capacity-scheduler.xml里配兩個(gè)隊(duì)列batch隊(duì)列給夜間批量作業(yè)interactive隊(duì)列給白天查詢(xún)各設(shè) 50% 上限。提交作業(yè)時(shí)用--queue batch指定隊(duì)列。5. 用 DistCp 做跨集群遷移時(shí)我必調(diào)的三個(gè)參數(shù)平臺(tái)跑起來(lái)之后遲早會(huì)遇到數(shù)據(jù)遷移——可能是路局合并也可能是從測(cè)試集群搬到生產(chǎn)集群。Hadoop 自帶的 DistCp 是最穩(wěn)的工具但默認(rèn)參數(shù)在鐵路貨運(yùn)這種大文件場(chǎng)景下會(huì)翻車(chē)。我一般會(huì)帶上這三個(gè)參數(shù)hadoop distcp \ -m 20 \ -bandwidth 100 \ -strategy dynamic \ -log /tmp/distcp.log \ hdfs://source-cluster/warehouse/ods/waybill \ hdfs://target-cluster/warehouse/ods/waybill-m 20控制同時(shí)啟動(dòng)的 map 數(shù)量默認(rèn)是 20 但實(shí)際取決于文件數(shù)鐵路貨運(yùn)的 ODS 層如果小文件多要適當(dāng)調(diào)大但別超過(guò)目標(biāo)集群的 DataNode 數(shù)量乘以 3。-bandwidth 100限制每個(gè) map 的帶寬為 100MB/s防止遷移把生產(chǎn)集群的網(wǎng)卡打滿(mǎn)這個(gè)參數(shù)在業(yè)務(wù)高峰期尤其重要。-strategy dynamic讓 DistCp 根據(jù)文件大小動(dòng)態(tài)分配比默認(rèn)的 uniform 策略更適合大小文件混雜的場(chǎng)景。遷移完必須做校驗(yàn)DistCp 自帶的-update只能保證文件存在不保證內(nèi)容一致。我習(xí)慣用hdfs dfs -count對(duì)比兩邊的文件數(shù)和總字節(jié)數(shù)再抽幾個(gè)分區(qū)做md5sum比對(duì)。有一次遷移完發(fā)現(xiàn)目標(biāo)集群少了三個(gè)分區(qū)查日志才發(fā)現(xiàn)是源集群某個(gè) DataNode 在遷移期間下線(xiàn)DistCp 靜默跳過(guò)了失敗的塊這種問(wèn)題不校驗(yàn)根本發(fā)現(xiàn)不了。最后一個(gè)習(xí)慣任何一次 DistCp 之前先拿一個(gè)分區(qū)做試遷移確認(rèn)權(quán)限、路徑、副本數(shù)都對(duì)了再全量跑。鐵路貨運(yùn)的數(shù)據(jù)動(dòng)輒幾十 TB跑一半失敗重來(lái)的時(shí)間成本太高后悔藥沒(méi)地方買(mǎi)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取