诊断常见 Hadoop 作业问题

大数据Beginner
立即练习

介绍

零售商的批处理昨天成功了,今天命令却报告错误。不读消息就反复重试,可能掩盖真正原因,也可能诱使你采取破坏性的捷径。输入缺失、服务地址错误、处理任务失败,需要不同的应对方式。

你将遵循一套简短诊断顺序:确认文件系统和连接,检查输入是否存在且可读,检查输出路径,再查看已接受应用的状态和日志。客户端错误可能发生在应用提交之前。已提交的应用有 YARN 身份,它的诊断信息能提供进一步证据。

本实验有意提供几种失败,包括一个会拒绝带特定标记记录的预编译教学应用。这些是受控的学习样例,不是随机基础设施故障。你将保留它们作为证据,并使用不同的输入和输出路径完成一次干净的 WordCount 运行。无需编写 Java、重装服务、格式化或大范围删除。所有实验数据均独立准备;请使用终端。

诊断连接与输入错误

在这一步中,你将读取真实客户端错误,区分服务地址错误和文件缺失。

先进入本地工作目录:

cd /home/labex/project

首先回顾已配置的文件系统:

hdfs getconf -confKey fs.defaultFS

应该是 hdfs://localhost:9000。现在故意让客户端连接端口 1,那里没有 NameNode 监听。下面的 -D 属性限制本次调用的连接重试次数,并设置 2,000 毫秒的连接超时,让故意触发的错误在有限时间内结束。它们不会编辑共享配置。

重定向 > file 2>&1 将普通输出保存到本地文件,并把错误输出发送到相同目标。下一条命令预期会失败。

hdfs dfs -Dipc.client.connect.max.retries=0 -Dipc.client.connect.timeout=2000 -ls hdfs://localhost:1/user/labex > /home/labex/project/output/connection-error.log 2>&1

读取保存的错误:

cat /home/labex/project/output/connection-error.log

查找连接失败或连接被拒绝的消息,以及错误地址。这发生在文件系统列表成功返回之前。不要格式化 HDFS 或重装服务;原因是命令使用了错误端点。使用默认路径回到已配置的端点:

hdfs dfs -ls /user/labex/job-diagnostics/data

应该看到 clean.txt 和 rejected.txt,说明连接正常。向这个健康的文件系统请求不存在的文件,是另一类问题。下一条命令预期会失败。

hdfs dfs -ls /user/labex/job-diagnostics/data/missing.txt > /home/labex/project/output/missing-input.log 2>&1

查看消息:

cat /home/labex/project/output/missing-input.log

应该报告指定路径不存在。使用熟悉的读取操作检查目标输入:

hdfs dfs -cat /user/labex/job-diagnostics/data/clean.txt

两行内容是 notebook pen 和 notebook folder。修正输入路径可以解决文件缺失问题;更改服务器配置则不能。请保留错误日志作为证据。

识别已存在的输出路径

在这一步中,你将观察作业为什么拒绝已存在的输出目录,并选择保留数据,而不是大范围删除。

初始化过程已准备一个空的 existing 结果目录,用来代表已预留的输出位置。查看这个目录条目:

hdfs dfs -ls -d /user/labex/job-diagnostics/results/existing

示例 MapReduce 输出格式要求创建一个新的输出目录。已有目录可能让客户端在处理应用被接受前就拒绝请求。下一条命令预期会失败。

hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.5.0.jar wordcount /user/labex/job-diagnostics/data/clean.txt /user/labex/job-diagnostics/results/existing > /home/labex/project/output/existing-output.log 2>&1

读取保存的消息:

cat /home/labex/project/output/existing-output.log

查找输出目录已存在的消息或 FileAlreadyExistsException。这是路径冲突,并不表示商品计数算法有误。

列出 YARN 已接受的应用:

yarn application -list -appStates ALL

这些客户端错误不应产生一个已完成的处理应用。客户端可能在提交准备期间联系集群服务或获取标识符;已接受的应用及其状态则是另一类证据。

你将在成功运行时保留预留目录,并使用新输出路径。移除整个 results 或删除原始输入,远远超出了问题所需的修改范围。

检查真实的失败应用

在这一步中,你将提交一个受控教学应用,并利用它的真实 YARN 身份和日志解释失败。

预置的 controlled-failure.jar 接受输入路径和新的输出路径。它的映射任务会故意拒绝标记 BAD_RECORD。你无需检查或编辑 Java 代码;这里是要区分已接受应用中的任务失败与之前的客户端错误。

先读取带标记的输入:

hdfs dfs -cat /user/labex/job-diagnostics/data/rejected.txt

它包含一行正常商品文本,后跟 BAD_RECORD。教学作业只进行一次映射尝试,避免反复重试相同的故意失败。下一条命令预期会失败。

hadoop jar /home/labex/project/tools/controlled-failure.jar /user/labex/job-diagnostics/data/rejected.txt /user/labex/job-diagnostics/results/failed-example > /home/labex/project/output/failed-job.log 2>&1

等待提示符,然后读取日志末尾:

tail -n 25 /home/labex/project/output/failed-job.log

与之前的情况不同,这次运行应该有已提交的 YARN 应用,以及任务失败的证据。使用与上个实验相同的应用列表模式,保存其实际 ID:

yarn application -list -appStates ALL | grep -o 'application_[0-9]*_[0-9]*' > /home/labex/project/output/failed-application-id.txt

查询并保存报告:

yarn application -status "$(cat /home/labex/project/output/failed-application-id.txt)" > /home/labex/project/output/failed-application-status.txt

读取报告:

cat /home/labex/project/output/failed-application-status.txt

找到应用身份、最终状态和诊断信息。最终状态应为 FAILED;报告是来自 YARN 的证据,并不是手写的失败标签。也读取真实聚合日志:

yarn logs -applicationId "$(cat /home/labex/project/output/failed-application-id.txt)" > /home/labex/project/output/failed-application.log

使用 grep 在其中查找已知的教学诊断消息:

grep 'Training input rejected' /home/labex/project/output/failed-application.log

消息指向带标记的记录。你已从笼统的命令非零结果,推进到由应用和任务日志支持的具体解释。保留这些证据,不要将每次失败都视为需要重启集群的理由。

修正批次选择并完成运行

在这一步中,你将使用干净输入和新的输出目录,再保留一份有证据支持的简短诊断记录。

目标报表输入是 clean.txt;被拒绝的文件只是教学样例。保留这两份原件。只针对干净文件提交熟悉的 WordCount 示例,使用新的结果目录:

hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.5.0.jar wordcount /user/labex/job-diagnostics/data/clean.txt /user/labex/job-diagnostics/results/successful-run > /home/labex/project/output/successful-job.log 2>&1

命令应该成功返回。输入包含两次 notebook、一次 pen 和一次 folder。读取结果:

hdfs dfs -cat '/user/labex/job-diagnostics/results/successful-run/part-*' | sort

预期计数如下:

folder 1
notebook 2
pen 1

成功运行的驱动程序日志包含应用 ID。sort -u 排序并删除重复的相同 ID 行,只保留本次调用的一个 ID:

grep -o 'application_[0-9]*_[0-9]*' /home/labex/project/output/successful-job.log | sort -u > /home/labex/project/output/successful-application-id.txt

确认实际成功应用的状态:

yarn application -status "$(cat /home/labex/project/output/successful-application-id.txt)"

最终状态应该为 SUCCEEDED。将之前的证据合并为一份本地诊断记录:

cat /home/labex/project/output/connection-error.log /home/labex/project/output/missing-input.log /home/labex/project/output/existing-output.log /home/labex/project/output/failed-application-status.txt > /home/labex/project/output/diagnosis.md

追加修复选择。printf 打印文本,\n 产生换行;>> 追加内容,不会替换已经保存的证据:

printf '\nRepair: select /user/labex/job-diagnostics/data/clean.txt and use the new /user/labex/job-diagnostics/results/successful-run output. Preserve original inputs and the existing result directory.\n' >> /home/labex/project/output/diagnosis.md

这份记录将错误、观察和行动联系起来。如果服务不可用或出现超出你权限的平台故障,应记录端点和消息并报告问题,不要重新格式化存储。对于这里学到的问题,选择具体路径或正确输入就足够了。

总结

你区分了连接错误、输入缺失、输出路径已存在,以及已接受的 YARN 应用中的任务失败。你使用真实应用状态和任务日志解释了一次受控拒绝,再用干净输入和新输出路径完成了正确批处理。

课程最后的挑战会将这些习惯与输入组织和权限结合起来,要求你使用已经练习过的方法,独立完成一个新批次。