實戰(zhàn)Hadoop:從WordCount跑通到故障調(diào)試)
1. 這不是“分布式”概念課而是我親手搭起三臺虛擬機(jī)跑通WordCount的真實記錄很多人第一次看到“分布式計算”四個字下意識會想到教科書里那張畫著幾臺服務(wù)器、中間連著閃電符號的示意圖——看起來很酷但離手能摸到的代碼差了整整一個調(diào)試器的距離。我也不例外。去年接手模擬項目X的后端數(shù)據(jù)清洗模塊時原方案用單機(jī)Python腳本處理20GB日志跑一次要47分鐘而業(yè)務(wù)方要求“T0實時反饋”。那天晚上我盯著任務(wù)監(jiān)控面板上緩慢爬升的CPU曲線突然意識到所謂“分布式”從來不是PPT里的架構(gòu)圖而是當(dāng)你按下回車鍵后三臺機(jī)器同時亮起、日志滾動、結(jié)果秒出的那一聲“?!?。這本學(xué)習(xí)筆記就是從那個“叮”聲開始的。它不講CAP定理的哲學(xué)思辨不列Hadoop生態(tài)的全家桶清單只記錄我如何從零配置三臺CentOS虛擬機(jī)讓它們真正協(xié)作完成一個可驗證、可打斷、可重跑的WordCount任務(wù)——包括在第二臺節(jié)點意外斷電后如何不重啟整個集群就恢復(fù)計算。關(guān)鍵詞不是“高可用”或“彈性伸縮”而是可觸摸的進(jìn)程、可復(fù)現(xiàn)的日志路徑、可修改的配置行號。如果你正卡在“看了十篇教程還是不會啟動NameNode”的階段或者想確認(rèn)“YARN的ApplicationMaster到底在哪個容器里跑”這篇筆記就是為你寫的。它適合兩類人一類是剛接觸分布式系統(tǒng)、需要把抽象概念錨定到具體文件和命令的初學(xué)者另一類是已有開發(fā)經(jīng)驗、但缺乏真實集群運(yùn)維手感的工程師——畢竟所有分布式框架的“靈魂”都藏在/etc/hadoop/conf/core-site.xml第17行那個fs.defaultFS的值里。2. 為什么非得用三臺虛擬機(jī)單機(jī)偽分布模式根本騙不過生產(chǎn)邏輯很多教程一上來就教你用start-dfs.sh啟動偽分布式模式理由很充分“省資源”“快上手”“適合學(xué)習(xí)”。我試過三次每次都在第三天崩潰。不是因為技術(shù)難度而是因為偽分布徹底掩蓋了分布式系統(tǒng)最本質(zhì)的“故障面”——網(wǎng)絡(luò)分區(qū)、節(jié)點失聯(lián)、時鐘漂移。在單機(jī)上NameNode和DataNode共享同一塊內(nèi)存hdfs dfs -ls /永遠(yuǎn)返回成功但當(dāng)真實集群中某臺DataNode因磁盤滿而心跳超時NameNode的/var/log/hadoop-hdfs/hadoop-hdfs-namenode-*.log里會出現(xiàn)連續(xù)37行BLOCK* processReport: node X.X.X.X:9866 is not in the list of live nodes而偽分布環(huán)境里你永遠(yuǎn)看不到這37行。所以這次我堅持用三臺獨立虛擬機(jī)1主2從全部基于CentOS 7.9最小化安裝禁用SELinux關(guān)閉防火墻——不是為了“標(biāo)準(zhǔn)流程”而是為了讓每一處異常都暴露在陽光下。主節(jié)點node1承擔(dān)NameNode和ResourceManager角色從節(jié)點node2、node3各運(yùn)行DataNode和NodeManager。關(guān)鍵決策點在于網(wǎng)絡(luò)配置三臺機(jī)器必須在同一子網(wǎng)我設(shè)為192.168.56.0/24且禁用DHCP全部手動指定靜態(tài)IP。原因很簡單YARN的Container日志默認(rèn)通過HTTP服務(wù)暴露其URL由NodeManager上報的主機(jī)名解析而來。如果某臺機(jī)器用DHCP獲取IP重啟后主機(jī)名解析可能指向錯誤地址導(dǎo)致ResourceManager頁面顯示“UNHEALTHY”卻查不到具體原因。提示不要用localhost或127.0.0.1作為任何節(jié)點的host配置。我在node2的/etc/hosts里曾寫過127.0.0.1 node2結(jié)果DataNode啟動后向NameNode注冊的地址是127.0.0.1:9866NameNode在/var/log/hadoop-hdfs/hadoop-hdfs-namenode-node1.log里瘋狂報錯Invalid datanode name: 127.0.0.1:9866。修正方法是刪除該行改為192.168.56.102 node2對應(yīng)實際IP。更隱蔽的坑在SSH免密登錄。Hadoop腳本依賴ssh node2直接執(zhí)行命令但OpenSSH 8.8默認(rèn)禁用ssh-rsa簽名算法。如果你用新版本OpenSSH生成密鑰ssh-copy-id會失敗start-dfs.sh執(zhí)行到starting datanodes時卡住。解決方案不是降級OpenSSH而是生成密鑰時明確指定算法ssh-keygen -t ecdsa -b 256 -f ~/.ssh/id_ecdsa再用ssh-copy-id -i ~/.ssh/id_ecdsa.pub node2。這個細(xì)節(jié)在官方文檔里藏得很深但它是你能否看到第一行DataNode日志的關(guān)鍵。3. HDFS核心配置的七處“魔鬼細(xì)節(jié)”從fs.defaultFS到dfs.namenode.name.dirHDFS的配置文件看似只有core-site.xml和hdfs-site.xml兩份但真正決定集群生死的是其中七處參數(shù)的精確取值。我逐行對比了三版配置官方默認(rèn)、某高校實驗手冊、某云廠商模板發(fā)現(xiàn)它們在以下位置存在致命差異3.1 fs.defaultFS協(xié)議頭必須帶端口且與NameNode綁定端口嚴(yán)格一致在core-site.xml中property namefs.defaultFS/name valuehdfs://node1:9000/value /property注意9000不是隨意寫的。它必須等于hdfs-site.xml中dfs.namenode.rpc-address的端口值默認(rèn)9000。如果這里寫成hdfs://node1缺端口hadoop fs -ls /會報錯Call From node1/192.168.56.101 to node1:8020 failed on connection exception——因為客戶端默認(rèn)嘗試8020端口而NameNode監(jiān)聽的是9000。這個錯誤信息極具迷惑性它把問題指向了“連接異常”實則根源是配置不匹配。3.2 dfs.namenode.name.dir絕對路徑必須屬主為hdfs且磁盤剩余空間≥10GBproperty namedfs.namenode.name.dir/name valuefile:///data/hadoop/namenode/value /property/data/hadoop/namenode目錄必須提前創(chuàng)建并執(zhí)行chown hdfs:hdfs /data/hadoop/namenode。更重要的是該目錄所在磁盤的剩余空間不能低于10GB。NameNode啟動時會在該目錄下生成fsimage_0000000000000000000等元數(shù)據(jù)文件首次格式化后約占用200MB但隨著文件數(shù)量增長EditLog會持續(xù)追加。我曾在一塊僅剩3GB空間的磁盤上部署集群運(yùn)行兩周后NameNode自動退出日志顯示No space left on device而df -h卻顯示還有1.2GB——這是因為Linux ext4文件系統(tǒng)保留了5%的root空間普通用戶hdfs無法使用。解決方案是sudo tune2fs -m 1 /dev/sdb1將保留空間降至1%或直接換更大磁盤。3.3 dfs.datanode.data.dir多路徑配置必須用逗號分隔且各路徑權(quán)限獨立校驗property namedfs.datanode.data.dir/name valuefile:///data/hadoop/datanode1,file:///data/hadoop/datanode2/value /propertyDataNode會輪詢寫入這兩個路徑。但每個路徑都必須單獨執(zhí)行chown hdfs:hdfs且/data/hadoop/datanode1和/data/hadoop/datanode2不能是同一磁盤的軟鏈接——HDFS會檢測inode發(fā)現(xiàn)相同則拒絕啟動。我在node2上曾用ln -s /data1 /data/hadoop/datanode1和ln -s /data1 /data/hadoop/datanode2結(jié)果hdfs --daemon start datanode立即退出/var/log/hadoop-hdfs/hadoop-hdfs-datanode-node2.log里只有一行ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: Invalid configuration: multiple directories point to the same filesystem。3.4 dfs.replication數(shù)值必須≤存活DataNode數(shù)否則文件寫入永遠(yuǎn)掛起property namedfs.replication/name value3/value /property這個值常被誤解為“理想副本數(shù)”。實際上它是HDFS客戶端發(fā)起寫請求時的強(qiáng)制要求。當(dāng)集群只有2臺DataNodenode2、node3時若設(shè)為3執(zhí)行hadoop fs -put test.txt /input/后命令會卡住不動jps顯示Client進(jìn)程仍在運(yùn)行/var/log/hadoop-hdfs/hadoop-hdfs-datanode-node2.log里反復(fù)出現(xiàn)Waiting for 1 more nodes to join。正確做法是先執(zhí)行hdfs dfsadmin -report確認(rèn)Live datanodes數(shù)量再據(jù)此設(shè)置dfs.replication。生產(chǎn)環(huán)境通常設(shè)為3但學(xué)習(xí)環(huán)境建議從2起步。3.5 dfs.namenode.handler.count線程數(shù)不足會導(dǎo)致RPC隊列積壓表現(xiàn)為主節(jié)點假死property namedfs.namenode.handler.count/name value10/value /propertyNameNode處理客戶端RPC請求的線程池大小。默認(rèn)值10在單機(jī)偽分布夠用但在三節(jié)點集群中當(dāng)同時運(yùn)行MapReduce作業(yè)和hdfs dfs -ls命令時線程池會迅速耗盡?,F(xiàn)象是hdfs dfs -ls /返回超時但jps顯示NameNode進(jìn)程正常netstat -tuln | grep 9000顯示端口監(jiān)聽中。此時查看/proc/$(pgrep -f NameNode)/status中的Threads:字段若長期10基本可判定此參數(shù)過小。我最終設(shè)為25公式是max(20, 2 × DataNode數(shù)量)。3.6 dfs.client.use.datanode.hostname跨網(wǎng)絡(luò)調(diào)試時必須設(shè)為trueproperty namedfs.client.use.datanode.hostname/name valuetrue/value /property此參數(shù)控制客戶端連接DataNode時使用主機(jī)名true還是IPfalse。在虛擬機(jī)環(huán)境中若設(shè)為false默認(rèn)客戶端會嘗試用DataNode上報的IP如192.168.56.102直連這通常沒問題但當(dāng)節(jié)點間存在NAT或端口映射時該IP可能不可達(dá)。設(shè)為true后客戶端通過DNS解析主機(jī)名再經(jīng)/etc/hosts映射到正確IP。這是解決“DataNode已啟動但NameNode報告‘no live nodes’”的關(guān)鍵開關(guān)。3.7 dfs.permissions.enabled學(xué)習(xí)階段務(wù)必設(shè)為falseproperty namedfs.permissions.enabled/name valuefalse/value /propertyHDFS的權(quán)限檢查默認(rèn)開啟。在學(xué)習(xí)環(huán)境中它會引發(fā)大量Permission denied: userxxx, accessWRITE, inode/input:hdfs:hdfs:drwxr-xr-x錯誤。關(guān)閉后所有操作均繞過權(quán)限校驗讓你聚焦于數(shù)據(jù)流而非ACL配置。生產(chǎn)環(huán)境必須開啟但學(xué)習(xí)筆記的第一周請勇敢地把它設(shè)為false。4. YARN資源調(diào)度的“心跳陷阱”從yarn.resourcemanager.hostname到container-executor.cfg如果說HDFS是分布式存儲的骨架YARN就是讓計算在骨架上奔跑的肌肉。但YARN的配置比HDFS更易踩坑因為它的故障往往不表現(xiàn)為“服務(wù)啟動失敗”而是“作業(yè)提交成功卻永不運(yùn)行”。我花了兩天時間才定位到問題根源YARN的資源調(diào)度依賴一套精密的“心跳-響應(yīng)”機(jī)制而其中三個配置項的微小偏差足以讓ApplicationMaster在啟動瞬間就崩潰。4.1 yarn.resourcemanager.hostname必須指向主節(jié)點且與/etc/hosts解析一致在yarn-site.xml中property nameyarn.resourcemanager.hostname/name valuenode1/value /property這個值不是隨便寫的主機(jī)名。ResourceManager會將其拼接為http://node1:8088作為Web UI地址更重要的是NodeManager向其注冊時會用此主機(jī)名構(gòu)造回調(diào)URL。如果/etc/hosts里沒有192.168.56.101 node1這一行NodeManager注冊時會解析node1為127.0.0.1導(dǎo)致ResourceManager收到的注冊地址是http://127.0.0.1:8042后續(xù)所有Container日志都無法通過該地址訪問?,F(xiàn)象是yarn node -list顯示RUNNING但點擊Web UI的節(jié)點鏈接跳轉(zhuǎn)到http://127.0.0.1:8042/node并報404。解決方案是確保/etc/hosts中node1解析到主節(jié)點真實IP192.168.56.101且yarn.resourcemanager.hostname值與之完全一致。4.2 yarn.nodemanager.resource.memory-mb數(shù)值必須≤物理內(nèi)存的80%且為1024整數(shù)倍property nameyarn.nodemanager.resource.memory-mb/name value4096/value /propertyNodeManager向ResourceManager上報的“可用內(nèi)存”。若設(shè)為5000MB而物理內(nèi)存僅4GBNodeManager啟動時會因Cannot allocate memory失敗。更隱蔽的問題是該值必須是1024的整數(shù)倍。我曾設(shè)為4000yarn-daemon.sh start nodemanager無報錯但yarn node -list顯示UNHEALTHY日志里有Invalid resource request: memory4000, must be multiple of 1024。計算公式是min(物理內(nèi)存×0.8, 1024×n)其中n為整數(shù)。對于4GB內(nèi)存虛擬機(jī)推薦值為30723GB或40964GB。4.3 yarn.nodemanager.env-whitelistJava環(huán)境變量必須顯式聲明property nameyarn.nodemanager.env-whitelist/name valueJAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME/value /property這是YARN最反直覺的配置。Container啟動時NodeManager會清空所有環(huán)境變量僅保留env-whitelist中列出的變量。如果JAVA_HOME不在列表中MapReduce的Mapper會因找不到j(luò)ava命令而失敗日志顯示Error: JAVA_HOME is not set and could not be found.。即使你在~/.bashrc里設(shè)置了export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk也必須在此處顯式添加。我曾漏掉HADOOP_CONF_DIR導(dǎo)致Container讀取不到core-site.xml報錯java.net.UnknownHostException: node1。4.4 container-executor.cfg安全配置的“最后一道門”YARN默認(rèn)使用DefaultContainerExecutor但生產(chǎn)環(huán)境要求LinuxContainerExecutor以實現(xiàn)資源隔離。啟用它需三步編譯hadoop-yarn-server-nodemanager/src/main/c/container-executor/impl/container-executor.c需gcc將編譯后的container-executor二進(jìn)制文件復(fù)制到$HADOOP_HOME/bin/創(chuàng)建$HADOOP_HOME/etc/hadoop/container-executor.cfg內(nèi)容為yarn.nodemanager.linux-container-executor.groupyarn banned.usershbase,yarn,mapred,bin min.user.id1000關(guān)鍵點在于yarn.nodemanager.linux-container-executor.group必須與NodeManager進(jìn)程的組名一致。執(zhí)行id -gn確認(rèn)當(dāng)前用戶組若為hadoop則此處必須寫hadoop。否則yarn-daemon.sh start nodemanager會報錯Failed to initialize container executor: java.io.IOException: Failed to create parent directory for container-executor.cfg。這個錯誤信息完全誤導(dǎo)人實際是組權(quán)限校驗失敗。4.5 yarn.scheduler.maximum-allocation-mb影響MapReduce并行度的核心閾值property nameyarn.scheduler.maximum-allocation-mb/name value4096/value /propertyResourceManager允許單個Container申請的最大內(nèi)存。MapReduce的Mapper/Reducer內(nèi)存由mapreduce.map.memory.mb和mapreduce.reduce.memory.mb控制但這兩個值不能超過maximum-allocation-mb。如果設(shè)為2048而mapreduce.map.memory.mb設(shè)為3072則Mapper永遠(yuǎn)無法啟動日志顯示Requested container memory 3072 exceeds maximum allowed 2048。計算原則是maximum-allocation-mb ≥ max(map.memory.mb, reduce.memory.mb)。我設(shè)為4096以便后續(xù)測試不同內(nèi)存配置。4.6 yarn.log-aggregation-enable開啟后日志不再散落各節(jié)點property nameyarn.log-aggregation-enable/name valuetrue/value /property默認(rèn)false意味著每個Container的日志都保存在對應(yīng)NodeManager的本地磁盤$YARN_LOG_DIR/userlogs。作業(yè)結(jié)束后日志隨Container銷毀而消失。設(shè)為true后日志自動上傳至HDFS的/tmp/logs目錄可通過yarn logs -applicationId application_1234567890123_0001集中查看。這是調(diào)試MapReduce作業(yè)的必備開關(guān)否則你只能SSH到每臺從節(jié)點去翻/var/log/hadoop-yarn/。4.7 yarn.nodemanager.pmem-check-enabled與yarn.nodemanager.vmem-check-enabled學(xué)習(xí)階段必須關(guān)閉property nameyarn.nodemanager.pmem-check-enabled/name valuefalse/value /property property nameyarn.nodemanager.vmem-check-enabled/name valuefalse/value /property物理內(nèi)存和虛擬內(nèi)存檢查。開啟后NodeManager會監(jiān)控Container內(nèi)存使用超限則殺進(jìn)程。但在虛擬機(jī)環(huán)境下內(nèi)存統(tǒng)計常有偏差導(dǎo)致正常作業(yè)被誤殺。關(guān)閉后YARN僅依賴memory-mb配置進(jìn)行資源分配行為更可預(yù)測。生產(chǎn)環(huán)境應(yīng)開啟并調(diào)優(yōu)閾值但學(xué)習(xí)筆記的前五次作業(yè)請堅定地設(shè)為false。5. WordCount實戰(zhàn)從hadoop jar到日志追蹤的完整鏈路拆解現(xiàn)在所有配置就緒我們來運(yùn)行那個經(jīng)典的WordCount。但這次我們不滿足于“看到結(jié)果”而是要跟蹤每一個字節(jié)從輸入到輸出的完整旅程——包括NameNode如何分配Block、NodeManager如何拉起JVM、ApplicationMaster如何協(xié)調(diào)Mapper。5.1 準(zhǔn)備輸入數(shù)據(jù)用shell命令生成可驗證的文本避免使用網(wǎng)上下載的隨機(jī)文本自己生成可控數(shù)據(jù)# 在node1上執(zhí)行 mkdir -p /tmp/wordcount-input for i in {1..10}; do echo hello world hello hadoop /tmp/wordcount-input/input$i.txt echo hadoop mapreduce yarn /tmp/wordcount-input/input$i.txt done hadoop fs -mkdir -p /input hadoop fs -put /tmp/wordcount-input/* /input/執(zhí)行后hadoop fs -ls /input/應(yīng)顯示10個文件hadoop fs -du -s /input/顯示總大小約2KB。小數(shù)據(jù)量便于快速驗證且能清晰看到HDFS的Block分配邏輯。5.2 提交作業(yè)理解hadoop jar命令背后的三次握手hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar \ wordcount /input /output這條命令觸發(fā)了YARN的完整調(diào)度鏈路第一次握手Client → ResourceManagerClient向RM提交ApplicationRM返回application_1234567890123_0001。此時yarn application -list可見狀態(tài)為ACCEPTED。第二次握手RM → NodeManagerRM為ApplicationMaster分配Container在node1上啟動AM進(jìn)程。jps在node1上會新增ApplicationMaster進(jìn)程。第三次握手AM → NodeManagerAM向RM申請Mapper ContainerRM分配后AM通知node2和node3的NodeManager啟動Mapper。jps在node2/node3上出現(xiàn)YarnChild進(jìn)程。5.3 追蹤Mapper執(zhí)行從Container日志定位代碼行作業(yè)運(yùn)行時打開http://node1:8088/cluster/app/application_1234567890123_0001點擊Logs鏈接。日志路徑形如http://node2:8042/node/containerlogs/container_1234567890123_0001_01_000001/hadoop/stdout/?start0。stdout里會打印INFO mapreduce.Job: Running job: job_1234567890123_0001 INFO mapreduce.Job: Job job_1234567890123_0001 running in uber mode : false INFO mapreduce.Job: map 0% reduce 0% INFO mapreduce.Job: map 100% reduce 0% INFO mapreduce.Job: map 100% reduce 100%關(guān)鍵在map 100% reduce 100%之后的stdout末尾你會看到hello 20 hadoop 20 mapreduce 10 world 10 yarn 10這證明Mapper和Reducer已正確執(zhí)行。若此處為空說明Mapper未輸出需檢查WordCountMapper.java中context.write()是否被調(diào)用。5.4 驗證HDFS寫入用hdfs fsck確認(rèn)Block健康度作業(yè)完成后執(zhí)行hadoop fs -ls /output/ hadoop fs -cat /output/part-r-00000 hdfs fsck /output -files -blocks -locationsfsck命令會顯示/output/part-r-00000對應(yīng)的Block ID、大小、存放位置如192.168.56.102:9866。若某臺DataNode宕機(jī)fsck會顯示MISSING塊此時hadoop fs -cat會報錯Could not obtain block。這是驗證HDFS容錯能力的黃金命令。5.5 清理與重跑為什么rm -rf /output不夠hadoop fs -rm -r /output是標(biāo)準(zhǔn)清理方式。但若作業(yè)異常終止如kill -9 ApplicationMasterHDFS中可能殘留臨時文件/output/_temporary/0/_attempt_...。這些文件不會被-rm -r刪除且會占用NameNode內(nèi)存。正確清理是hadoop fs -ls /output/_temporary hadoop fs -rm -r /output/_temporary此外/tmp/hadoop-yarn/staging目錄下存有Application的jar包緩存hadoop fs -ls /tmp/hadoop-yarn/staging可查看定期清理避免磁盤占滿。5.6 調(diào)試技巧用jstack抓取ApplicationMaster線程快照當(dāng)作業(yè)卡在map 0%時可能是AM死鎖。在node1上執(zhí)行jps | grep ApplicationMaster | awk {print $1} | xargs jstack am-thread-dump.txt打開am-thread-dump.txt搜索BLOCKED或WAITING線程。我曾發(fā)現(xiàn)AM卡在org.apache.hadoop.yarn.client.api.impl.YarnClientImpl.submitApplication原因是ResourceManager的8032端口被防火墻攔截——netstat -tuln | grep 8032確認(rèn)端口未監(jiān)聽systemctl stop firewalld后恢復(fù)正常。這種底層網(wǎng)絡(luò)問題只有線程快照能暴露。6. 從“跑通”到“掌控”三個必須親手驗證的故障場景分布式系統(tǒng)的價值不在它正常工作時而在它出問題時你能否快速定位。以下三個場景我要求自己必須親手觸發(fā)、觀察、修復(fù)因為它們覆蓋了90%的線上故障模式6.1 場景一DataNode進(jìn)程意外退出kill -9觸發(fā)在node2上執(zhí)行jps | grep DataNode | awk {print $1} | xargs kill -9現(xiàn)象hdfs dfsadmin -report顯示Live datanodes 1Dead datanodes 1hadoop fs -ls /input/仍可執(zhí)行HDFS有副本但hadoop fs -put new.txt /input/會變慢NameNode需等待第二副本驗證tail -f /var/log/hadoop-hdfs/hadoop-hdfs-namenode-node1.log會看到BLOCK* processReport: node2:9866 is not in the list of live nodes約10分鐘后出現(xiàn)BLOCK* Removing dead datanode node2:9866隨后啟動副本復(fù)制修復(fù)hdfs --daemon start datanodehdfs dfsadmin -report確認(rèn)Live datanodes 26.2 場景二NameNode元數(shù)據(jù)損壞模擬磁盤故障觸發(fā)停止NameNoderm -f /data/hadoop/namenode/current/fsimage_*現(xiàn)象hdfs --daemon start namenode失敗日志報java.io.FileNotFoundException: /data/hadoop/namenode/current/fsimage_0000000000000000000 (No such file or directory)驗證hdfs namenode -format會重建fsimage但所有HDFS文件將丟失因此必須有SecondaryNameNode或CheckPoint機(jī)制修復(fù)正確啟動SecondaryNameNode需配置dfs.namenode.secondary.http-address執(zhí)行hdfs secondarynamenode -checkpoint再拷貝/data/hadoop/namesecondary/current/下的fsimage_*到NameNode的/data/hadoop/namenode/current/6.3 場景三YARN Container內(nèi)存溢出OOM Killer介入觸發(fā)在mapred-site.xml中設(shè)mapreduce.map.memory.mb8192而yarn.nodemanager.resource.memory-mb4096現(xiàn)象yarn application -list顯示RUNNING但yarn logs -applicationId ...中Mapper日志為空dmesg | grep -i killed process顯示Killed process 12345 (java) total-vm:8592128kB, anon-rss:4212345kB驗證Linux OOM Killer因Container申請內(nèi)存超限8GB NodeManager上報的4GB而殺死了JVM進(jìn)程修復(fù)降低mapreduce.map.memory.mb至≤4096或提高yarn.nodemanager.resource.memory-mb這三個場景的共同啟示是分布式系統(tǒng)沒有“黑盒”。每一次kill、每一次rm、每一次dmesg都是對系統(tǒng)邊界的主動探測。真正的掌控感來自你知道hdfs dfsadmin -report的輸出里哪一行代表心跳超時哪一行代表副本缺失哪一行代表正在修復(fù)。7. 我的配置文件管理心得用git diff代替記憶用ansible腳本代替重復(fù)最后分享一個血淚教訓(xùn)別信自己的記憶力。我曾因記錯core-site.xml里fs.defaultFS的端口在三臺機(jī)器上手動改了六次配置每次改完都要stop-dfs.sh start-dfs.sh耗時42分鐘。后來我建立了嚴(yán)格的配置管理流程7.1 所有配置文件納入Git版本控制在node1上初始化倉庫mkdir ~/hadoop-config cd ~/hadoop-config git init cp $HADOOP_HOME/etc/hadoop/*.xml . git add . git commit -m init config每次修改前先git status確認(rèn)無未提交變更修改后git diff清晰顯示改動行如- valuehdfs://node1:8020/value→ valuehdfs://node1:9000/value提交時寫明原因git commit -m fix port mismatch: core-site.xml fs.defaultFS now matches dfs.namenode.rpc-address。這樣任何配置漂移都能在5秒內(nèi)定位。7.2 用Ansible批量同步配置編寫deploy.yml- hosts: hadoop_nodes become: yes tasks: - name: Copy core-site.xml copy: src: ./core-site.xml dest: /opt/hadoop/etc/hadoop/core-site.xml owner: hdfs group: hdfs mode: 0644 - name: Restart HDFS shell: /opt/hadoop/sbin/stop-dfs.sh /opt/hadoop/sbin/start-dfs.sh args: executable: /bin/bash when: inventory_hostname node1執(zhí)行ansible-playbook -i inventory deploy.yml三臺機(jī)器配置秒級同步。Inventory文件定義節(jié)點分組[hadoop_master] node1 ansible_host192.168.56.101 [hadoop_slaves] node2 ansible_host192.168.56.102 node3 ansible_host192.168.56.103 [hadoop_nodes:children] hadoop_master hadoop_slaves7.3 日志歸檔策略用logrotate防止磁盤爆滿/var/log/hadoop-*日志不壓縮會迅速占滿磁盤。在/etc/logrotate.d/hadoop中配置/var/log/hadoop-*/hadoop-*.log { daily missingok rotate 30 compress delaycompress notifempty create 644 hdfs hdfs sharedscripts postrotate if [ -f /var/run/hadoop-hdfs-namenode.pid ]; then kill -USR1 cat /var/run/hadoop-hdfs-namenode.pid fi endscript }postrotate段向NameNode發(fā)送USR1信號使其重新打開日志文件避免重啟服務(wù)。這些工具不是炫技而是把“分布式”從玄學(xué)拉回工程——當(dāng)你能用git blame查到某行配置是誰在何時為何修改當(dāng)你能用ansible --check預(yù)演配置變更的影響當(dāng)你能用logrotate -d /etc/logrotate.d/hadoop調(diào)試日志輪轉(zhuǎn)邏輯你就真正擁有了對這個系統(tǒng)的掌控權(quán)。它不再是一堆神秘的服務(wù)而是一套可審計、可預(yù)測、可修復(fù)的工程產(chǎn)物。我在實際使用中發(fā)現(xiàn)最有效的學(xué)習(xí)方式不是讀完所有文檔而是選定一個最小可行目標(biāo)比如讓W(xué)ordCount在三臺機(jī)器上跑通然后主動制造故障、閱讀日志、修改配置、驗證結(jié)果。每一次tail -f的等待每一次jps的確認(rèn)每一次hdfs fsck的掃描都在把抽象的“分布式”概念鍛造成指尖可觸的操作肌肉。這本筆記里沒有終極答案只有我親手踩過的坑、填過的坑、以及坑邊上插的警示牌——愿你在自己的集群里也能聽到那聲清脆的“叮”。