Hadoop分布式集群部署与故障排查实战指南
1. 项目概述:这不是一次“装个软件”的操作,而是一次对分布式系统思维的实地拉练
你点开这篇文字,大概率不是为了找一个“Hadoop安装教程”——网上能搜出几百篇带截图、带命令行的步骤文档,但真正用过 Hadoop 做过真实数据处理的人,十有八九会在第三步卡住:namenode 启动失败、datanode 连不上、yarn 的 ResourceManager 页面打不开、或者 MapReduce 任务提交后永远显示 ACCEPTED 却不运行。这不是你手生,也不是配置写错了几个空格,而是你正站在一个经典认知断层上:单机思维和分布式思维之间,隔着一堵看不见的墙。我在金融风控团队搭过日均 20TB 日志的离线计算平台,在电商中台维护过三年的 Hadoop+Hive 生产集群,也带过十几届校招新人从零部署伪分布式环境。所有踩过的坑、重装过的系统、抓包分析过的 RPC 调用、翻烂的 Apache 官方 JIRA issue,最后都沉淀成一句话:Hadoop 不是“装好就能跑”,它是你第一次亲手把一台机器“掰开”,让它的存储、计算、调度三部分分别住在不同进程里,再用网络把它们重新焊死在一起的过程。这篇文章要带你做的,就是亲手完成这道焊接。它不讲“Hadoop 是什么”这种教科书定义(那一页纸就能写完),而是聚焦在“为什么必须这么配”“哪个参数改错会导致整个集群静默死亡”“当 web UI 显示红色告警时,第一眼该盯哪三个日志文件”。关键词里的 “Towards AI” 和 “Medium” 只是原始出处标记,我们彻底剥离平台属性,回归技术本体——所有操作基于 Apache Hadoop 3.3.6(当前 LTS 最稳版本),所有路径、端口、用户权限都按生产级最小权限原则设计,所有命令都经过 Ubuntu 22.04 + OpenJDK 11 + systemd 环境实测。如果你刚学完 MapReduce 编程模型却连本地 WordCount 都跑不起来,如果你在云上开了三台 ECS 却发现 datanode 死活注册不上,或者你正被公司要求两周内上线一个测试集群但毫无头绪——这篇文章就是为你写的。它不承诺“一键部署”,但保证你合上页面时,能独立诊断 85% 的常见启动故障,并理解背后每一层网络、Java、Linux 的协作逻辑。
2. 核心架构解构:先拆开,再组装——Hadoop 四大组件的真实分工与依赖链
2.1 HDFS:不是“分布式硬盘”,而是“带心跳的文件切片保险柜”
很多人把 HDFS 理解成“把大文件切成块存在多台机器上”,这没错,但漏掉了最关键的两个字:心跳。HDFS 的 namenode(NN)和 datanode(DN)之间不是简单的“我存你管”关系,而是一套精密的生存监测系统。NN 每隔 3 秒向每个 DN 发送心跳请求(heartbeat),DN 必须在 10 秒内响应并附带自身存储块报告(block report)。如果连续 10 次心跳失败(即约 3 分钟),NN 就会将该 DN 标记为“dead”,并触发副本复制流程——这才是 HDFS 高可用的底层逻辑。所以当你看到hdfs dfsadmin -report输出里某个 DN 状态是DEAD,别急着重启服务,先查/var/log/hadoop-hdfs/hadoop-hdfs-datanode-*.log里有没有java.net.ConnectException: Connection refused,这往往意味着 DN 进程根本没起来,或者防火墙拦住了 9866(DN 数据传输端口)和 9867(DN HTTP 端口)。HDFS 的核心配置文件hdfs-site.xml里,dfs.namenode.http-address和dfs.datanode.http.address这两个参数必须指向可被集群内所有节点解析的主机名,而不是localhost或127.0.0.1。我见过太多人因为/etc/hosts里只写了127.0.0.1 localhost,导致 DN 启动后向http://localhost:9870注册,结果 NN 在另一台机器上根本收不到注册请求。正确的做法是在每台机器的/etc/hosts里明确写出所有节点的 IP 和主机名映射,例如:
192.168.1.10 namenode 192.168.1.11 datanode1 192.168.1.12 datanode2然后在core-site.xml的fs.defaultFS中写hdfs://namenode:9000,而不是hdfs://192.168.1.10:9000。这样做的好处是:当某台机器 IP 变更时,只需改 hosts,不用动所有配置文件。这是运维老手才懂的“配置解耦”技巧。
2.2 YARN:资源调度器不是“分配 CPU”,而是“拍卖时间片+空间席位”的双轨制
YARN 的 ResourceManager(RM)和 NodeManager(NM)协作模式,常被类比为“机场塔台+登机口”。但这个类比不够准——塔台只管航班起降时间,而 YARN 的 RM 同时拍卖两样东西:CPU 时间片(vcores)和内存席位(memory-mb)。一个 Container 的启动,必须同时竞拍成功这两样资源。这就是为什么你常看到日志里报Failed to allocate container: Insufficient memory,但free -h显示内存充足。真相是:YARN 默认把物理内存的 80% 划给 NM 管理(由yarn.nodemanager.resource.memory-mb控制),剩下的 20% 留给系统和 OS 进程。假设你有 32GB 内存的机器,yarn.nodemanager.resource.memory-mb设为24576(24GB),而你的 MapReduce 任务申请了32768MB 内存,NM 就会直接拒绝,哪怕物理内存还有空闲。更隐蔽的坑在 vcores:yarn.nodemanager.resource.cpu-vcores默认等于机器 CPU 核数,但 Java 进程的 GC 线程会抢占 vcore,导致实际可用 vcore 少于理论值。我在测试 Spark on YARN 时就遇到过:8 核机器设vcores=8,但 Spark Executor 启动后频繁 Full GC,监控显示 CPU 使用率 95%,而 YARN UI 显示 vcore 使用率仅 40%。最后发现是 JVM 参数-XX:+UseG1GC的并发线程数占用了额外 vcore,解决方案是把vcores提到 10,并在yarn-site.xml中增加yarn.nodemanager.vmem-pmem-ratio=3.0(放宽虚拟内存限制)。YARN 的本质,是把硬件资源抽象成可编程的“数字席位”,而你的任务代码,就是一张张需要精确填写席位编号(container id)和使用时长(timeout)的电子机票。
2.3 MapReduce:不是“写两个函数”,而是“在数据不动的前提下移动计算”的空间换时间哲学
MapReduce 的经典误区是:“map 函数处理一行,reduce 函数汇总结果”。这在单机模拟时成立,但在 HDFS 上完全错误。真实流程是:Map 阶段的输入分片(InputSplit)必须与 HDFS 的 block 对齐。HDFS 默认 block size 是 128MB,那么一个 1GB 的文本文件会被切成 8 个 block,每个 block 存在 3 个副本(默认 replication=3)。MapTask 的调度策略是“数据本地性优先”:RM 会尽量把 MapTask 分配到存储着该 block 副本的机器上执行。这意味着,如果你的 datanode1 存着 block1 的副本,那么处理 block1 的 map task 就大概率在 datanode1 的 NM 上启动。这就是“移动计算,而非移动数据”的核心——省掉的是跨网络传输 128MB 数据的时间。但问题来了:如果mapred-site.xml里mapreduce.input.fileinputformat.split.minsize设得过大(比如 256MB),系统就会强行把两个 block 合并成一个 split,导致 map task 必须从远程 datanode 拉取数据,性能暴跌。我实测过:处理 10GB 日志,split size 从 128MB 改为 256MB,作业耗时从 8 分钟涨到 15 分钟。另一个致命细节是 shuffle 阶段:map 输出的 key-value 对不是直接发给 reduce,而是先写入本地磁盘(mapreduce.cluster.local.dir指定路径),再由 reduce task 主动拉取。这个磁盘路径必须是高速 SSD 且有足够剩余空间,否则 map task 会因磁盘 IO 等待超时而失败。我们在生产环境强制要求:mapreduce.cluster.local.dir必须挂载在独立 NVMe 盘,且预留 50GB 以上空间,否则集群健康检查直接告警。
2.4 组件间依赖链:启动顺序不是“习惯”,而是由 RPC 协议栈决定的硬约束
Hadoop 集群的启动顺序(HDFS → YARN → MapReduce)常被当作运维口诀背诵,但没人告诉你为什么不能反过来。答案藏在 RPC 协议栈里:HDFS 的 namenode 启动后,会监听 8020 端口(IPC 端口)提供ClientProtocol接口;YARN 的 ResourceManager 启动后,需要调用这个接口检查 HDFS 是否可用(通过FileSystem.get()创建连接),才能初始化其内部的RMStateStore(状态存储,默认存在 HDFS 的/rmstate目录下)。如果你先启 YARN,它会在日志里疯狂打印org.apache.hadoop.ipc.RemoteException: java.io.IOException: Filesystem closed,因为 NN 根本没起来,FileSystem实例创建失败。同理,MapReduce 的 historyserver 依赖 YARN 的 timeline service,而 timeline service 又依赖 HDFS 存储应用历史数据。这个依赖链是由 Java 接口继承关系和配置文件中的fs.defaultFS、yarn.resourcemanager.hostname等硬编码 URL 决定的,不是脚本顺序能绕过的。所以我的集群初始化脚本里,永远有三道锁:
hdfs namenode -format成功后,才执行hdfs --daemon start namenodehdfs dfsadmin -safemode wait返回 0(安全模式退出)后,才执行yarn --daemon start resourcemanageryarn node -list | grep RUNNING输出至少一个节点后,才启动mapred --daemon start historyserver这三步缺一不可,跳过任何一步,后续服务都会在日志里留下“Connection refused”或“UnknownHostException”的幽灵错误。这不是保守,而是对分布式系统 RPC 调用失败重试机制的尊重——Hadoop 默认重试 10 次,每次间隔 1 秒,你等 10 秒不如手动确认。
3. 实操部署全链路:从单机伪分布到三节点集群的逐层穿透
3.1 环境筑基:JDK 与 SSH 的“隐形地基”必须夯实
Hadoop 对 Java 版本极其敏感。官方明确支持 JDK 8 和 JDK 11,但 JDK 17+ 会因javax.xml.bind包移除导致hdfs namenode -format报NoClassDefFoundError。我选 OpenJDK 11.0.22(2023 年 10 月 LTS 版),安装后必须验证三件事:
# 1. 确认 JAVA_HOME 指向正确路径(不是 /usr/bin/java 的软链接) echo $JAVA_HOME # 应输出 /usr/lib/jvm/java-11-openjdk-amd64 # 2. 验证 java 命令和 javac 命令版本一致 java -version && javac -version # 两者输出必须都是 11.0.22 # 3. 关键!检查 JAVA_HOME 下的 jre/lib/ext 目录是否存在(Hadoop 3.x 依赖此路径加载 native lib) ls $JAVA_HOME/jre/lib/ext/ | grep hadoop # 应无输出,但目录必须存在SSH 配置常被忽略,但它决定了集群能否“信任”。Hadoop 启动脚本(如start-dfs.sh)本质是用ssh命令批量登录各节点执行hdfs --daemon start datanode。所以必须:
- 所有节点关闭 SELinux(
sudo setenforce 0)和防火墙(sudo ufw disable),否则 ssh 会因端口拦截失败; - 在 namenode 节点生成免密密钥:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa; - 将公钥分发到所有节点(包括自己):
ssh-copy-id -i ~/.ssh/id_rsa.pub namenode、ssh-copy-id -i ~/.ssh/id_rsa.pub datanode1; - 最关键一步:在每台机器的
/etc/ssh/sshd_config中,确保PubkeyAuthentication yes和AuthorizedKeysFile .ssh/authorized_keys未被注释,然后重启 sshd:sudo systemctl restart sshd。 我曾因sshd_config里AuthorizedKeysFile被改成%h/.ssh/authorized_keys(意为用户主目录下的 .ssh),导致ssh-copy-id把公钥写到了/root/.ssh/authorized_keys,而 Hadoop 脚本以hdfs用户身份运行,找不到密钥,最终所有 datanode 启动失败。这个坑,没有日志提示,只能靠ssh -v hdfs@datanode1查看详细连接过程才能发现。
3.2 伪分布式实战:用一台机器模拟集群的“最小可行闭环”
伪分布式(Pseudo-Distributed Mode)不是玩具,而是理解组件交互的显微镜。它把 NN、DN、RM、NM 全部跑在同一台机器的不同 JVM 进程里,但严格遵循分布式协议。配置要点如下:
core-site.xml(全局基础配置)
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> <!-- 注意:这里用 localhost,因为所有服务在同一台 --> </property> </configuration>hdfs-site.xml(HDFS 专属配置)
<configuration> <property> <name>dfs.replication</name> <value>1</value> <!-- 伪分布只需 1 副本,避免磁盘爆满 --> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///usr/local/hadoop/hadoop_data/hdfs/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///usr/local/hadoop/hadoop_data/hdfs/datanode</value> </property> </configuration>yarn-site.xml(YARN 专属配置)
<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>localhost</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>4096</value> <!-- 根据机器内存调整,16GB 内存机器设 4GB --> </property> </configuration>mapred-site.xml(MapReduce 配置)
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> <!-- 强制走 YARN,不是 local 模式 --> </property> </configuration>格式化 namenode 并启动:
# 创建数据目录(必须提前建好,否则启动报错) sudo mkdir -p /usr/local/hadoop/hadoop_data/hdfs/{namenode,datanode} sudo chown -R hdfs:hdfs /usr/local/hadoop/hadoop_data # 格式化(仅首次执行!) sudo -u hdfs hdfs namenode -format # 启动 HDFS start-dfs.sh # 自动启动 namenode 和 datanode 进程 # 启动 YARN start-yarn.sh # 自动启动 resourcemanager 和 nodemanager # 验证:jps 命令应看到 5 个进程 jps # 输出应包含:NameNode, DataNode, ResourceManager, NodeManager, Jps此时访问http://localhost:9870(HDFS UI)和http://localhost:8088(YARN UI),能看到活跃节点数为 1。执行经典 WordCount:
# 创建输入目录 sudo -u hdfs hdfs dfs -mkdir -p /input # 上传测试文件(本地文件) echo "hello world hello hadoop" > /tmp/input.txt sudo -u hdfs hdfs dfs -put /tmp/input.txt /input # 运行 MapReduce(Hadoop 自带示例) sudo -u hdfs hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /input /output # 查看输出 sudo -u hdfs hdfs dfs -cat /output/part-r-00000如果输出hadoop 1hello 2world 1,恭喜,你的伪分布式闭环已打通。注意:所有命令前加sudo -u hdfs是因为 HDFS 进程以hdfs用户运行,权限隔离是安全基石。
3.3 三节点集群部署:从“单机幻觉”到“真实网络拓扑”的跨越
当伪分布跑通,下一步是三节点(1 NN+RM + 2 DN+NM)真实集群。关键变化是:所有localhost必须替换成真实主机名,且 DNS 解析必须 100% 可靠。
网络规划表
| 角色 | 主机名 | IP 地址 | 服务 |
|---|---|---|---|
| Master | namenode | 192.168.1.10 | NameNode, ResourceManager, SecondaryNameNode |
| Worker1 | datanode1 | 192.168.1.11 | DataNode, NodeManager |
| Worker2 | datanode2 | 192.168.1.12 | DataNode, NodeManager |
workers文件(替代旧版slaves)在 namenode 的$HADOOP_HOME/etc/hadoop/workers文件中,写入:
datanode1 datanode2core-site.xml(Master 节点)
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://namenode:9000</value> <!-- 指向 Master 主机名 --> </property> </configuration>hdfs-site.xml(所有节点)
<configuration> <property> <name>dfs.namenode.http-address</name> <value>namenode:9870</value> <!-- Web UI 地址 --> </property> <property> <name>dfs.namenode.rpc-address</name> <value>namenode:8020</value> <!-- RPC 地址,DN 注册用 --> </property> <property> <name>dfs.datanode.http.address</name> <value>0.0.0.0:9864</value> <!-- DN Web UI,0.0.0.0 允许外部访问 --> </property> </configuration>yarn-site.xml(所有节点)
<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>namenode</value> <!-- RM 必须在 Master --> </property> <property> <name>yarn.nodemanager.remote-app-log-dir</name> <value>/app-logs</value> <!-- 日志统一存 HDFS --> </property> </configuration>部署流程(在 namenode 执行)
# 1. 将配置文件同步到所有 worker for node in datanode1 datanode2; do scp $HADOOP_HOME/etc/hadoop/*.xml $node:$HADOOP_HOME/etc/hadoop/ done # 2. 格式化 namenode(仅 Master 执行一次) sudo -u hdfs hdfs namenode -format # 3. 启动 HDFS(自动 ssh 到 workers 启 datanode) start-dfs.sh # 4. 启动 YARN(自动 ssh 到 workers 启 nodemanager) start-yarn.sh # 5. 在 Master 启动 SecondaryNameNode(非必须,但推荐) hdfs --daemon start secondarynamenode验证集群状态
# 查看 HDFS 状态 sudo -u hdfs hdfs dfsadmin -report | grep -E "(Live|Dead|Decommissioned)" # 正常应显示 Live datanodes : 2 # 查看 YARN 节点 yarn node -list -all | grep RUNNING # 应显示 2 个 RUNNING 节点 # 检查进程(在各节点执行 jps) # namenode: NameNode, ResourceManager, SecondaryNameNode, Jps # datanode1: DataNode, NodeManager, Jps # datanode2: DataNode, NodeManager, Jps如果hdfs dfsadmin -report显示Live datanodes : 0,立刻检查datanode1的/var/log/hadoop-hdfs/hadoop-hdfs-datanode-datanode1.log,90% 的概率是java.net.UnknownHostException: namenode—— 这说明datanode1的/etc/hosts里没配192.168.1.10 namenode。记住:Hadoop 集群里,DNS 解析失败比网络不通更致命,因为后者会报 timeout,前者直接抛异常中断流程。
3.4 云环境适配:AWS EC2 上的 Hadoop 集群避坑指南
在 AWS 上部署 Hadoop,最大的陷阱是安全组(Security Group)配置。EC2 默认安全组只开放 22 端口,而 Hadoop 需要开放数十个端口。必须一次性放行以下端口组:
| 端口 | 服务 | 协议 | 开放范围 |
|---|---|---|---|
| 22 | SSH | TCP | 你的 IP |
| 9000 | HDFS IPC | TCP | 所有节点(自定义源:sg-xxxx) |
| 9870 | HDFS Web UI | TCP | 你的 IP |
| 9864 | DataNode Web UI | TCP | 你的 IP |
| 8088 | YARN Web UI | TCP | 你的 IP |
| 8030-8033 | YARN RPC | TCP | 所有节点 |
| 9866-9867 | DataNode RPC & HTTP | TCP | 所有节点 |
特别注意:
- 不要用
0.0.0.0/0开放所有端口,这是严重安全隐患; - “所有节点”指集群内所有 EC2 实例,应通过安全组 ID(如
sg-12345678)作为源,而非 IP 段; - 在
yarn-site.xml中,yarn.resourcemanager.webapp.address必须设为0.0.0.0:8088,否则 YARN UI 只能本机访问; - EC2 的
hostname默认是ip-172-31-xx-xx.ec2.internal,但 Hadoop 配置中建议用自定义主机名(如namenode),并在/etc/hosts中绑定私有 IP,避免因 DNS 解析延迟导致启动超时。
4. 故障排查实战手册:从日志红字到秒级定位的黄金四步法
4.1 黄金四步法:定位问题的标准化流水线
面对 Hadoop 启动失败或任务卡死,我从不靠猜。我的标准动作是四步循环:
- 看 UI 红字:先打开
http://namenode:9870和http://namenode:8088,UI 上的红色告警(如Dead Nodes: 1、Unhealthy Nodes: 1)是最高优先级线索; - 查进程存活:在对应节点执行
jps,确认关键进程(NameNode/DataNode/ResourceManager/NodeManager)是否在列表中; - 读最新日志:进入
$HADOOP_HOME/logs/,用tail -n 100 hadoop-*-namenode-*.log | grep -i "error\|exception\|failed"快速抓取错误堆栈; - 验网络连通:用
telnet namenode 8020测试 NN RPC 端口是否可达,用curl -I http://datanode1:9864测试 DN Web 端口。
这四步覆盖了 95% 的问题。下面是我整理的高频故障速查表:
| 现象 | 可能原因 | 定位命令 | 解决方案 |
|---|---|---|---|
start-dfs.sh后jps看不到 DataNode | datanode进程启动即退出 | tail -n 50 $HADOOP_HOME/logs/hadoop-*-datanode-*.log | 检查dfs.datanode.data.dir目录权限,chown -R hdfs:hdfs /path/to/data |
YARN UI 显示0 active nodes | NodeManager 未启动或注册失败 | jps看是否有NodeManager;tail -n 50 $HADOOP_HOME/logs/yarn-*-nodemanager-*.log | 检查yarn.nodemanager.resource.memory-mb是否超过物理内存,调小该值 |
MapReduce 任务卡在ACCEPTED | ResourceManager 无法分配 Container | yarn application -status <app_id>;yarn node -list | 检查yarn.resourcemanager.scheduler.class是否为CapacityScheduler,并确认队列default有资源 |
hdfs dfs -ls /报Connection refused | Namenode 未监听 8020 端口 | `netstat -tuln | grep 8020;sudo lsof -i :8020` |
| SecondaryNameNode 启动失败 | 无法连接 Namenode | tail -n 50 $HADOOP_HOME/logs/hadoop-*-secondarynamenode-*.log | 检查fs.defaultFS是否指向hdfs://namenode:9000,且namenode可解析 |
4.2 一个经典案例:DataNode 启动后立即消失的完整复盘
现象:在 datanode1 上执行hdfs --daemon start datanode,jps瞬间看到DataNode进程,2 秒后消失,hdfs dfsadmin -report显示Dead datanodes: 1。
排查过程:
- UI 红字:HDFS UI 无明显告警,但
Live datanodes为 0; - 查进程:
jps确认 DataNode 进程闪退; - 读日志:
tail -n 100 $HADOOP_HOME/logs/hadoop-hdfs-datanode-datanode1.log发现关键错误:ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: Exception in secureMain java.io.IOException: All directories in dfs.datanode.data.dir are invalid: "/usr/local/hadoop/hadoop_data/hdfs/datanode" - 验网络:
telnet namenode 8020成功,排除网络问题。
根因分析:dfs.datanode.data.dir目录权限错误。Hadoop 要求该目录必须由hdfs用户拥有,且不能有 group 或 other 的写权限(即权限必须是755或700)。我之前执行了chmod 777 /usr/local/hadoop/hadoop_data/hdfs/datanode,Hadoop 认为这是不安全的,直接拒绝启动。
解决方案:
sudo chown -R hdfs:hdfs /usr/local/hadoop/hadoop_data/hdfs/datanode sudo chmod 755 /usr/local/hadoop/hadoop_data/hdfs/datanode sudo -u hdfs hdfs --daemon start datanode再次jps,DataNode 进程稳定运行,hdfs dfsadmin -report显示Live datanodes : 1。
这个案例揭示了一个核心原则:Hadoop 的安全模型比你想象的更严格。它宁可启动失败,也不接受“看似能用”的宽松权限。所有数据目录、日志目录、pid 目录,都必须用chown hdfs:hdfs和chmod 755严格加固。
4.3 生产环境必备:日志轮转与磁盘空间守护脚本
Hadoop 日志不清理,半年就能吃掉 100GB 磁盘。我写的自动化清理脚本(放在/usr/local/bin/hadoop-log-clean.sh):
#!/bin/bash # 清理 Hadoop 日志,保留最近 7 天 LOG_DIR="/usr/local/hadoop/logs" find $LOG_DIR -name "*.log.*" -type f -mtime +7 -delete find $LOG_DIR -name "*.out" -type f -mtime +7 -delete # 清理 HDFS 临时文件(/tmp/hadoop-*) find /tmp -maxdepth 1 -name "hadoop-*" -type d -mtime +1 -exec rm -rf {} \;加入 crontab 每日凌晨 2 点执行:
0 2 * * * /usr/local/bin/hadoop-log-clean.sh >> /var/log/hadoop-log-clean.log 2>&1同时,我用df -h监控/usr/local/hadoop/hadoop_data分区,当使用率 >85% 时,自动触发告警邮件。这个脚本已在三个生产集群稳定运行两年,零事故。
5. 扩展能力图谱:Hadoop 不是终点,而是大数据生态的中央枢纽
5.1 与 Spark 的共生:为什么 Spark on YARN 是生产首选
很多人纠结“Hadoop vs Spark”,这是伪命题。Spark 本身不提供存储,它需要 HDFS 作为底层文件系统。Spark on YARN 的优势在于:资源复用。同一个 YARN 集群,可以同时运行 MapReduce 作业(批处理)、Spark Streaming(实时流)、甚至 Flink 任务(事件驱动)。我管理的集群里,70% 的 ETL 用 Spark SQL,20% 的报表用 Hive on Tez,10% 的风控模型用 MapReduce,全部共享同一套 YARN 资源池。
部署 Spark on YARN 的关键配置(spark-defaults.conf):
spark.master yarn spark.submit.deployMode client spark.yarn.jars hdfs://namenode:9000/spark-jars/* spark.yarn.archive hdfs://namenode:9000/spark-archive.zip注意:spark.yarn.jars必须指向 HDFS 上的 jar 包路径,而不是本地路径。我通常把$SPARK_HOME/jars/下所有 jar 上传到 HDFS 的/spark-jars目录,这样所有节点都能通过 HDFS 协议拉取,避免 jar 包分发失败。
5.2 与 HBase 的协同:HDFS 是骨,HBase 是肉
HBase 是构建在 HDFS 之上的 NoSQL 数据库。它的 RegionServer 进程直接读写 HDFS 的/hbase目录。这意味着:HBase 的稳定性高度依赖 HDFS 的健康度。当 HDFS 出现大量 Dead Datanode 时,HBase 的 RegionServer 会因无法写入 WAL(Write-Ahead Log)而崩溃。因此,HBase 集群的监控,必须把hdfs dfsadmin -report的输出纳入告警体系。我在 Prometheus 中配置了自定义 exporter,当Live datanodes数量 < 总节点数的 80% 时,自动触发 HBase 服务降级预案。
5.3 云原生演进:Kubernetes 上的 Hadoop?现实很骨感
有人问:“能不能把 Hadoop 搬到 K8s?” 答案是:技术上可行,但生产不推荐。原因有三:
- 存储绑定难题:HDFS 的 DataNode 必须绑定本地磁盘(
dfs.datanode.data.dir),而 K8s 的 PersistentVolume 通常是网络存储(NFS/Ceph