
做Hadoop运维这些年我遇到过不少深夜被叫起来处理集群故障的情况。其中有一类问题最让人头疼文件读不出来、数据块报告损坏、NameNode起不来。很多刚接触HDFS的朋友第一反应是重启试试但搞不好会把问题越搞越大。今天我想把两个绕不开的运维技能摊开来讲透彻hadoop fsck命令的用法以及NameNode元数据损坏后的修复思路。这两个东西是HDFS运维的基本功掌握了它们大部分文件系统层面的坑你都能从容应对。这篇文章适合正在维护HDFS集群的工程师也适合准备深入Hadoop生态的技术爱好者。我会从实际运维场景出发把fsck命令的每个参数、每行输出的含义讲清楚再带你走一遍NameNode元数据修复的完整流程包括fsimage、edits日志、安全模式这些核心概念。最后我还会把自己踩过的坑和排查技巧整理成速查表希望对你有实际帮助。1. 项目背景与问题诊断1.1 NameNode元数据到底存了什么在动手修之前得先把NameNode的家底摸清楚。我经常给团队的新人打一个比方NameNode就像一个大图书馆的总索引卡柜它不存放真正的书数据块但每一本书放在哪个书架、借出去几本、哪些书缺页了全都记录在案。HDFS的数据本身分散在DataNode上而文件如何组成目录树、每个文件分成哪些块、每个块存在于哪些DataNode这些信息全部由NameNode管理。具体到磁盘上NameNode的元数据是由两大部分组成的fsimage和edits log。fsimage是某个时间点命名空间的完整快照相当于图书馆每隔一段时间盘一次库存的记录edits log则是从快照之后每一次变更的流水账比如新建文件、删除目录、修改副本数。NameNode启动时会把fsimage加载到内存然后逐条回放edits log最终构建出最新的命名空间。这两类文件存储位置由dfs.namenode.name.dir参数指定建议配置多个目录分散在不同磁盘上就像图书馆的重要账本复印两份放在不同房间。很多元数据损坏的悲剧根源就在于只配了一个目录或者两块盘同时老化。除了fsimage和edits还有几个容易被忽略的文件seen_txid记录了最新的事务IDVERSION文件保存了集群ID和namespaceID这些在恢复时都可能成为关键线索。1.2 什么情况下需要跑fsck和元数据修复fsck这个名字源于Linux里的文件系统检查工具在HDFS里它的全称是File System Check职责是对整个分布式文件系统做健康体检。很多朋友误以为只有文件系统出问题了才需要跑fsck其实它是一个非常实用的日常巡检工具。我来说说我在生产环境里遇到过需要跑fsck的几种典型场景。第一种是客户端报错读文件失败比如File ... could only be replicated to 0 nodes这时候需要用fsck确认是文件真的损坏了还是网络或节点问题。第二种是DataNode磁盘损坏导致一些块丢失需要知道影响面有多大。第三种是扩容或缩容节点后需要检查副本分布是否均匀。第四种是定期巡检每周跑一次全量fsck比任何监控都踏实。NameNode元数据修复的场景就更紧急了。典型症状包括NameNode进程启动时报java.io.IOException: NameNode is not formatted启动后一直卡在安全模式不出来日志里刷FileNotFoundException直接提示fsimage file is corrupt或edits log解析失败。这些情况一旦出现必须立即停止盲目重启冷静定位问题再决定用哪条恢复路径。2. fsck命令从入门到实战2.1 基础命令与常用参数fsck命令的入口在Hadoop发行版中通常有两个写法hadoop fsck和hdfs fsck新版中hdfs fsck是推荐写法但hadoop fsck也仍然兼容。命令核心语法非常简单第一个参数就是你要检查的路径可以是根目录/也可以是某个具体目录或文件。先看一段最基础的检查hdfs fsck /这条命令会检查整个文件系统的健康状态最终输出一段Summary告诉你总文件数、总块数、损坏块数、副本不足的块数等关键指标。如果Status是HEALTHY恭喜你系统没大毛病如果出现CORRUPT字样就要继续深挖。真正干活的时候光一个裸命令远远不够。我列几个我用的最多的参数组合# 列出每个文件的块信息适合定位具体哪个文件有问题 hdfs fsck /path/to/file -files -blocks # 在块信息基础上追加位置和机架信息排查拓扑和本地性 hdfs fsck / -files -blocks -locations -racks # 统计副本数检查是否存在过度复制或不足复制 hdfs fsck / -files -blocks -replicaDetails # 查看打开待写的文件这些文件本身就是不完整的 hdfs fsck / -openforwrite还有一个容易被忽略的细节fsck会对正在写入的文件显示一个特殊标记。如果一个文件因为客户端崩溃没有正常close它的最后一个块会一直处于构建状态fsck会把它归到Open For Write类别这并不算损坏处理方式是等租约过期或者手动恢复租约。2.2 读懂fsck输出很多人跑完fsck看到一堆英文输出只知道复制粘贴求助其实关键信息就那几行。我建议把注意力集中在Summary段的这几个指标上。Total blocks表示整个系统管理的块总数。Corrupt blocks是损坏的块数这个数字只要不为0就要警觉但先别慌因为HDFS有副本机制一个块损坏了只要还有至少一个有效副本系统是可以自动修复的。真正致命的指标是Missing replicas它表示完全丢失的副本数如果某个块的所有副本都没了通过fsck就无法挽回了只能从上层备份恢复或者接受数据丢失。Under replicated blocks表示副本数低于配置值的块比如默认副本数是3实际只有2。这种情况常见于节点宕机或磁盘故障只要集群容量足够HDFS会自动补副本但如果长期处于这种状态说明集群可能有健康问题。我拿一次实际巡检的输出做注释Status: CORRUPT Total size: 524288000 B Total dirs: 10 Total files: 256 Total blocks (validated): 512 Minimally replicated blocks: 508 (99.2 %) Over-replicated blocks: 2 (0.4 %) Under-replicated blocks: 6 (1.2 %) Mis-replicated blocks: 3 (0.6 %) Corrupt blocks: 4 (0.8 %) Missing replicas: 4 Number of>hdfs fsck /data/important -files -blocks -locations fsck_report.txt跑完这行命令打开report文件找到带CORRUPT字样的文件行。典型输出长这样/user/hive/warehouse/tmp_file 52428800 bytes, 1 block(s): OK blk_1073742845_1000002 len52428800 Live_repl1 CORRUPTLive_repl1说明这个块的可用副本只剩1个而且这一份在DataNode本地做block scan的时候发现校验失败被打上了CORRUPT标记。这种情况下如果还有别的DataNode上存在未知副本HDFS会自动复制如果彻底没副本了这个文件就成了孤儿只能从快照或备份拉取。定位坏块的具体存储位置可以用下面的命令hdfs fsck /path/to/file -files -blocks -locations输出会包含类似这样的信息DatanodeInfoWithStorage[192.168.1.7:9866, DatanodeStorage[DS-xxx, DISK], 已损坏]看到已损坏三个字就可以锁定这台机器了。接下来上服务器查磁盘健康看datanode日志里的corrupt记录。我见过不少次是磁盘坏道导致的checksum失配这时候果断把该DataNode隔离掉替换磁盘比在软件层面反复折腾有效得多。3. NameNode元数据修复完整实操3.1 元数据损坏的典型场景NameNode元数据损坏这件事虽然不常发生但一旦发生就是集群级事故。我总结下来主要有三类场景。第一类是fsimage文件本身损坏。表现为NameNode启动时直接报Cannot load image或Image file ... is corrupt之类的异常。这种情况通常是因为磁盘出现了不可纠正的I/O错误或者人为误操作覆盖了文件。还有一种隐蔽的情况fsimage和md5校验文件不匹配也会导致启动失败。第二类是edits log损坏。edits log是增量日志如果里面的记录有截断或者格式错乱回放的时候就会在中途失败。这种情况最麻烦因为edits log往往不止一个文件坏了一个中间的前后的日志就衔接不上了。第三类是fsimage和edits之间的事务ID断裂。比如fsimage是最新检查点但edits log的起始事务ID和fsimage的末尾事务ID对不上NameNode就不知道从哪开始回放。这个问题在手动拷贝备份文件的时候特别容易踩雷。3.2 fsimage与edits的恢复路径在具体操作前先理解一下元数据的组成结构。一个正常的NameNode元数据目录通常长这样$ dfs.namenode.name.dir/current/ ├── fsimage_0000000000000000293 ├── fsimage_0000000000000000293.md5 ├── edits_0000000000000000001-0000000000000000293 ├── edits_inprogress_0000000000000000294 ├── seen_txid └── VERSIONfsimage_293表示这个快照包含到事务ID 293为止的所有状态。edits_1-293是从事务1到293的变更日志edits_inprogress_294是正在写入中的事务日志。如果NameNode正常关闭这个inprogress文件会转成正式的edits段文件。恢复路径的选择核心取决于你还有哪些好的元数据源。我按优先级排列第一优先如果有定期备份比如异地拷贝fsimage和edits直接拿备份来恢复。这也是很多公司忽略的一点只备份数据不看元数据真要出事才发现备份根本跑不起来。第二优先如果集群配置了Checkpoint Node或者Secondary NameNode老版本它们的磁盘上保存了一份最近的fsimage合并结果。这台节点的状态可能比主NameNode旧一点但可以用来救急。第三优先主NameNode本地的fsimage损坏了但edits log完好可以用edits来回放恢复状态。最后的手段只剩一个损坏的fsimage可以尝试用离线工具强行解析里面能读出来的部分但这样做要接受部分数据丢失。3.3 手动修复与安全模式操作下面我带大家走一遍我实际操作过的恢复流程以fsimage损坏但edits完整为例子。第一步立即让集群进入安全模式防止元数据灾情扩大。hdfs dfsadmin -safemode enter安全模式相当于HDFS的只读保护态客户端不能写数据NameNode也不做块副本调整这能避免在元数据不一致的情况下继续写入导致二次破坏。第二步备份当前的元数据目录。即使是坏的文件也要原样保存一份万一恢复失败还能回头分析。cp -r $dfs.namenode.name.dir /backup/namenode_broken_$(date %Y%m%d)第三步停掉NameNode进程。这里我要特别提醒别用kill -9尽量用受控方式停止让它有机会把内存中最后的edits刷盘。第四步分析损坏程度。用HDFS官方自带工具查看fsimage内容这一步可以确认损伤范围hdfs oiv -p XML -i fsimage_* -o /tmp/fsimage_dump.xml如果oiv能成功解析说明fsimage至少头部和主体没完全损坏可以尝试用工具部分恢复。如果这把工具都失败了就走回放edits路线。第五步回放edits恢复元数据。关键操作是把edits日志和fsimage放到一个干净的目录里然后启动NameNode进入强制恢复模式hdfs namenode -recover命令行会给出几个选项选择Recover and restart模式的对应序号NameNode会尝试载入fsimage并按顺序回放edits。如果fsimage损坏到无法载入可以尝试用一组最小的fsimage比如手动构造一个空镜像配上完整edits回放这样至少能把目录结构和文件元数据重建出来。第六步恢复完成后退出安全模式并验证hdfs dfsadmin -safemode leave hdfs fsck / -files -blocks3.4 备份恢复的完整流程如果你的环境比较好有从Checkpoint Node同步过来的fsimage恢复会更顺利。我来说说具体的替换流程。首先找到Checkpoint Node的元数据目录正常情况下它有一个比较新的fsimage_xxx。看一下seen_txid确认它比主NameNode的edits起点更接近最新状态。然后把主NameNode停掉把它的current目录整体改名备份再把Checkpoint Node的current目录完整拷贝过来。mv current current_broken cp -r /checkpoint_node_path/current . chown -R hdfs:hdfs current这一步有个关键动作检查seen_txid和edits的衔接。如果Checkpoint Node的fsimage比主NameNode的edits日志要旧你需要把主NameNode上比fsimage更新的edits段也拷贝过来放到同一个current目录里NameNode启动时才能继续回放。启动主NameNode观察日志。正常启动后NameNode会先进入安全模式等它加载完元数据并上报足够数据块后自动退出安全模式。如果卡住多半是安全模式阈值设置过高或DataNode上报的块不完整这时可以手动强制退出但要确认关键文件的副本数真的够。4. 常见问题与排查技巧实录4.1 典型问题速查表这一节我直接把多年攒下来的问题排查经验整理成表格方便你遇到事情时按图索骥。症状可能原因排查与处理fsck输出CORRUPT但文件能读该文件有冗余副本坏块还没影响读取继续观察坏的副本会被自动删除重建无需干预fsck显示Missing replicas所有副本都丢失或有副本在离线节点查是否有节点宕机等待恢复若确认数据丢失只能从备份恢复NameNode启动报fsimage损坏磁盘I/O错误或文件被覆盖用oiv尝试解析或用edits回放最后考虑Checkpoint Node备份启动后长期停留在安全模式元数据回放卡住或DataNode上报不足看NameNode日志定位回放卡点检查DataNode连通性必要时强制退出安全模式恢复元数据后部分目录不见了fsimage和edits衔接断层检查seen_txid与edits段是否匹配找到断档区间补回edits数据节点报告block checksum failed磁盘坏道或数据写入时损坏隔离该DataNode下线后更换磁盘让HDFS自动复制副本4.2 实操心得与避坑清单讲几个我认为特别重要的实操心得。第一个心得不要把fsck当万能的。fsck能查出文件系统层面的损坏但它不能修复一个所有副本都被物理破坏的块。所以生产环境一定要有更上层的备份策略比如开启hdfs快照功能或者定期把关键数据同步到其他存储。我见过不止一次因为完全没有备份最后只能眼睁睁看着一个月的计算结果消失。第二个心得恢复元数据之前先把原来的文件目录整体复制一份这不是浪费时间而是给自己留一条退路。很多人在焦虑状态下操作一个回车覆盖了原本还能抢救的文件那才叫真正的绝望。技术上叫先加固再动刀。第三个心得操作edits日志时要分清已经完成的段和正在写入的段。inprogress文件不能手动重命名或改动否则NameNode不知道该从哪继续写日志。如果一定要动先把NameNode正常停掉把inprogress转成正式edits段再开始恢复操作。第四个心得平时就把NameNode元数据目录单独放在性能好、健康状态明确的磁盘上并且定期做快照。这个低成本习惯能让你在真正出事的时候省去80%的恢复时间。第五个心得所有涉及元数据的文件操作一律用hdfs用户身份去执行。用root操作后文件属主变了NameNode启动时会直接报Permission denied这个问题看似小但特别容易在慌乱中出现。结尾说了这么多我最想强调的就是一件事HDFS的元数据是整个集群的心脏而fsck和元数据修复是保护这颗心脏的两把手术刀。平时多花十分钟跑一次巡检、看一眼fsck输出远比故障发生后通宵恢复要值。我在实际运维中也会定期把fsck报告存下来前后对比很多潜在问题在那个阶段就能被提前发现。最后再分享一个小技巧可以把fsck检查封装成一个带超时和告警的脚本每周定时把报告推送到内部群这样老板问起来你手里永远有数据。这个内容后续还能扩展成完整的HDFS巡检体系比如结合DataNode的磁盘监控和机架感知下次有机会再和大家细聊。