Hadoop 3.3.3集群部署实战:从单机伪分布式到完全分布式配置与调优
2026/8/31 16:17:43 网站建设 项目流程

简介:Apache Hadoop 3.3.3 是面向大数据分布式计算领域的核心开源框架,适用于高校学生、大数据初学者及运维开发人员,用于搭建本地伪分布式或集群环境,开展HDFS存储、MapReduce计算、YARN资源调度等基础实验与工程实践。压缩包共22536个文件,涵盖18870个HTML文档(含完整API参考与配置手册)、763个JPG/GIF/PNG图像(含架构图与流程示意图)、449个JAR包(含核心运行时依赖)、75个Shell脚本(含hdfs/yarn启动与管理工具)以及大量XML配置模板、CSS/JS前端资源和原生库SO文件(如libhadoop.so、libhdfs.so等),全面支撑编译、部署、调试与二次开发。资源大小为615.16MB,结构完整、开箱即用。已有640人学习下载,读者可直接获取官方二进制发行版、全量文档体系、可执行脚本及原生扩展库,快速构建稳定可靠的大数据处理平台,避免源码编译复杂性,显著降低入门门槛。

1. 项目概述:hadoop-3.3.3.tar.gz 到底在解决什么问题

最近团队又在搭新的数据处理环境,我从归档里翻出这个老熟人——hadoop-3.3.3.tar.gz。如果你也是做数据平台、数仓底座或者离线计算集群的,那对这份 500 多 MB 的压缩包绝对不陌生。Apache Hadoop 这一套生态,从 2006 年诞生到现在,依然是很多企业离线数据处理的事实标准。虽然现在 Spark、Flink 满天飞,但几乎所有跑在 YARN 上的计算引擎,底层都离不开 HDFS 这套分布式存储和 YARN 的资源调度。

这次我把 3.3.3 版本的部署过程、配置细节和踩坑点完完整整走了一遍,从单机伪分布式到完全分布式集群,把每一步的关键决策都记录下来。这篇文章适合两类人:一类是刚接触 Hadoop、想在一台机器上快速跑通 Hello World 的新手;另一类是准备搭正式集群、需要理解每个配置项到底在起什么作用的运维和开发同学。不管你是哪种,照着这篇文章走一遍,至少能少踩 80% 的坑。

先把这个项目的核心拆一下。hadoop-3.3.3.tar.gz是 Apache Hadoop 3.3.3 版本的官方源码编译产物,采用 tar.gz 格式打包,解压即用。3.3.x 是 Hadoop 3.x 系列里比较成熟的稳定分支,修复了一堆 3.2.x 时代的 NameNode 内存泄漏和 YARN 调度器在超大规模集群下的性能问题。相比 3.5.0 那种刚发布不久的新版本,3.3.3 在生产环境的验证案例更多,踩坑参考也更好找。

如果只从功能上看,Hadoop 3.x 和 2.x 最大的分水岭就是支持了NameNode 的多个备节点(Observer NameNode)基于纠删码(Erasure Coding)的存储方案YARN 的 GPU/FPGA 资源调度。这些能力让 Hadoop 3.3.3 在存储利用率和异构计算支持上,比老版本上了一个台阶。而 3.3.3 这个具体版本号,则在 3.3.0 和 3.3.2 的基础上修了一大批 CVE 漏洞和稳定性问题,比如 HDFS 的OpenFile并发处理、RBF(Router-Based Federation)的跨命名空间挂载问题。

2. 版本选型思路:为什么我最终选了 3.3.3 而不是最新版

很多朋友一看官网,发现 Apache Hadoop 已经出到 3.5.0 了,就会纠结:我是不是应该直接用最新版?这里我想先分享一下版本选型的逻辑,因为这直接决定了你后续所有配置和踩坑路线。

2.1 3.3.3 与新版本的定位差异

Apache Hadoop 的版本迭代节奏和大数据生态不太一样,它不像某些前端框架那样追求快速发布,而是更看重稳定性。3.3.x 系列从 2021 年发布 3.3.0 开始,到现在经历了大量生产环境验证。我选择 3.3.3 的核心原因有三条:

第一,Java 版本兼容面广。3.3.3 官方支持 Java 8 和 Java 11,而 3.5.0 虽然也支持,但官方已经开始把默认构建往 Java 11/17 方向倾斜。对于很多企业内部还停留在 JDK 8 的环境来说,3.3.3 是更平滑的选择。很多时候不是我们不想升 JDK,而是历史任务、老 Spark 版本、自研框架都绑死在 JDK 8 上,为了一个存储层把整个计算生态都升一遍,风险太大了。

第二,生态组件兼容性。Hive、Spark、Flink、HBase 这些上层组件,官方在适配时往往滞后于 Hadoop 的新版本发布周期。以 Spark 为例,Spark 3.2.x 和 3.3.x 官方测试过和 Hadoop 3.3.x 的兼容性,但如果你去看 Spark 的官方文档,它对 Hadoop 3.5.0 的支持说明相对较少,很多 SQL 引擎自带的 Shuffle 插件在 Hadoop 3.5.0 上还没有足够的生产级验证。换句话说,当你用 3.5.0 跑 Spark 任务时,万一出问题,你很难判断是 Hadoop 的 bug 还是 Spark 的适配问题。

第三,社区经验和文档积累。这里要说得直白一点——用 3.3.3 遇到问题,你去搜解决方案,能翻到大量真实的生产案例和踩坑帖;用 3.5.0 遇到问题,很多时候只能啃源码或者在社区里等待回复。我见过太多人追新版,最后卡在一个很冷门的 bug 上几天出不来。做基础设施的,稳比新重要得多。

2.2 3.3.3 的关键能力盘点

既然决定用 3.3.3,那至少得知道这个版本能给我们带来什么。我挑几个实际用得上、感受明显的能力说一下。

首先是HDFS 纠删码(Erasure Coding)。原先是默认三副本存储,一份数据占三倍空间,纠删码用 RS-6-3 等算法,一份数据只占 1.4 倍空间左右,可靠性还更高。这在冷数据存储场景下能把存储成本砍掉一半。唯一要注意的是,纠删码不适合随机写、小文件多的场景,它更适合大文件、顺序读写的离线数仓底层。3.3.3 对纠删码的支持已经相当成熟,hdfs ec命令可以直接在线配置。

其次是YARN 的资源类型扩展。3.3.3 支持在yarn-site.xml里自定义资源类型,比如 GPU、FPGA,配合resource-types.xml可以给节点配置 GPU 数量和控制任务调度的资源维度。这意味着你可以让一个 Hadoop 集群同时跑 CPU 任务和 GPU 训练任务,而不是再单独搭一套资源管理。

第三是NameNode 的性能优化。3.3.x 针对大规模目录和文件数量做了不少优化,包括改进的 XAttr 处理、更高效的 EditLog 批量同步,在千万级文件数量下,NameNode 响应延时有明显改善。这一点可能很多同学感知不到,但如果你的集群文件数是百万级以上,升级到 3.3.x 后 NameNode 的 GC 频率会降低不少。

3. 部署前环境准备与核心决策

在真正解压hadoop-3.3.3.tar.gz之前,有几个前置工作必须做扎实。这个阶段最容易被赶进度的人跳过,结果后面全是在补锅。我按自己的实操顺序来梳理。

3.1 主机规划与角色分配

假如你现在要搭一个三节点的生产测试集群,我建议这样分配角色:

节点角色分配说明
node1NameNode、ResourceManager、SecondaryNameNode主节点,建议内存 32G 以上
node2DataNode、NodeManager计算存储节点
node3DataNode、NodeManager计算存储节点

生产环境我一般不建议把 NameNode 和 ResourceManager 拆到两台机器上,倒不是技术上行不通,而是一方面这两个角色都吃内存,拆开更能分散风险;另一方面如果真的需要高可用,NameNode 的 Active/Standby 集群本身就有两台物理机,再多拆就没有必要了。

如果只有一台机器拿来学习,那可以走伪分布式模式,所有角色都在这台机器上,但这时候要注意,内存资源是共享的,默认配置下 NameNode 和 DataNode 各自都要分配 1G 以上内存,加上 ResourceManager 和 NodeManager,一台 8G 内存的机器跑起来已经有点吃力了。建议内存至少 12G。

3.2 JDK 版本选择和安装细节

前面说了,3.3.3 支持 Java 8 和 Java 11。我在实际部署中选的是 Java 8 的最后一个免费版本(OpenJDK 8u392 之后),为什么不选 Java 11?原因很简单,生态兼容。企业内部如果还要跑 Hive on MR 的老任务,或者有一些基于 MR 的二次开发,JDK 8 是兼容性最保险的选择。而且 3.3.3 官方文档明确写了支持 Java 8,那就没必要给自己找不痛快。

安装 JDK 的时候建议直接用tar.gz包解压安装,然后配置/etc/profile

export JAVA_HOME=/opt/jdk8 export PATH=$PATH:$JAVA_HOME/bin

配置完记得source /etc/profile,然后执行java -version验证。这里有个小坑:Hadoop 的启动脚本会优先使用JAVA_HOME环境变量,如果配置不生效,NameNode 会直接启动失败,报错信息是Error: JAVA_HOME is not set and could not be found。我看到过很多次这问题,最后发现不是没装 Java,而是/etc/profile没生效。

3.3 SSH 免密登录配置

集群部署的第二个前置条件就是 SSH 免密。Hadoop 的启动脚本在分发和执行远程命令时,需要通过 SSH 登录到其他节点,如果每次都要输密码,start-dfs.sh就会被卡住。

配置很简单,在主节点上执行:

ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa ssh-copy-id node1 ssh-copy-id node2 ssh-copy-id node3

ssh-copy-id会把公钥追加到目标机器的authorized_keys文件里。这里注意,如果你自己改了 SSH 端口,需要加-p参数。

验证方式:

ssh node2 hostname

如果你看到返回的是node2的主机名而不是让你输密码,那就说明通了。很多同学忽略了这一步验证,结果后面集群起一半、报错连接超时,再回来补,浪费时间。

3.4 目录规划与文件下载

我这边的目录规划也比较固定,分享一下:

/opt/hadoop # Hadoop 安装目录 /opt/hadoop/data # HDFS 数据目录(DataNode 存储目录) /opt/hadoop/logs # 日志目录 /opt/hadoop/tmp # 临时目录

为什么要单独把数据和安装目录分开?因为 DataNode 的数据目录如果和安装目录放在同一个分区,数据量涨起来之后磁盘空间满了,会把安装目录也一起堵死,到时候连日志都写不出来。这个分区规划问题,很多新手根本想不到,等出了问题再收拾就晚了。

下载hadoop-3.3.3.tar.gz我推荐从 Apache 官方镜像站获取,直接去镜像站列表里选一个离你近的,下载后一定要校验 SHA-512。官方下载页旁边会提供对应的.sha512文件,用下面的命令校验:

echo "<官方sha512值> hadoop-3.3.3.tar.gz" | sha512sum -c -

如果输出OK,说明文件没有损坏。这一步不能省,我之前有一次下载了不完整的包,解压后集脚本能运行,但第二天格式化 NameNode 一直失败,最后还是回到校验文件才发现问题。

4. 单机伪分布式部署全流程实操

先别急着直接上集群,我建议第一次部署的读者,一定先在单机上跑通伪分布式模式。这样你能把 HDFS、YARN 的核心配置和启动流程理解清楚,同时方便排查问题。单机模式跑通了,再往集群扩展就是改配置和分发文件的事。

4.1 解压安装与环境变量配置

拿到hadoop-3.3.3.tar.gz之后,执行:

tar -zxvf hadoop-3.3.3.tar.gz -C /opt/hadoop

解压完成后,目录名是hadoop-3.3.3。我习惯把它重命名成hadoop,方便后面版本升级时切换:

cd /opt/hadoop mv hadoop-3.3.3 hadoop

然后编辑/etc/profile添加环境变量:

export HADOOP_HOME=/opt/hadoop/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop

这里有必要解释一下这几个环境变量的作用:HADOOP_HOME是 Hadoop 的安装根目录,所有脚本都靠它定位命令;PATH加路径是为了让你直接敲hdfsyarn就能找到可执行文件;HADOOP_CONF_DIR指定配置文件目录,这个变量在你用hadoop-daemon.sh启停单个进程时特别有用。

还有一个环境变量必须改,就是$HADOOP_HOME/etc/hadoop/hadoop-env.sh里的JAVA_HOME

vi /opt/hadoop/hadoop/etc/hadoop/hadoop-env.sh

找到export JAVA_HOME=这一行,改成你自己的 JDK 路径。我见过很多人只配置了系统的JAVA_HOME,没改hadoop-env.sh,结果start-dfs.sh执行到hdfs --daemon start namenode时还是报找不到 Java。这是因为 Hadoop 的某些守护进程脚本会覆盖系统环境变量,直接加载hadoop-env.sh里的值。

4.2 核心配置文件修改:core-site.xml 和 hdfs-site.xml

伪分布式模式下,核心配置集中在两个文件里。先改core-site.xml

<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop/tmp</value> </property> </configuration>

fs.defaultFS不解释了,就是你的 NameNode 地址。hadoop.tmp.dir是 NameNode、DataNode 存放元数据、数据块的根目录,这个目录一定要提前建好,并且权限要可写。我把 tmp 目录独立出来,就是为了防止系统/tmp被清理导致元数据丢失。曾经有个生产事故:服务器重启时/tmp被 systemd 的 tmpfiles 机制清空,HDFS 元数据没了,虽然是属于该丢的,数据全挂在 0 Byte 下,最后还是恢复了才堪堪救回来。这个配置真的别偷懒。

再改hdfs-site.xml

<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///opt/hadoop/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///opt/hadoop/data/datanode</value> </property> <property> <name>dfs.namenode.http-address</name> <value>0.0.0.0:9870</value> </property> </configuration>

伪分布式模式副本数只能配 1,因为你只有一个 DataNode,配成 3 会出现Zero targets found的调度错误。dfs.replication这个参数等扩展到三节点集群时改回 3 就行。dfs.namenode.name.dirdfs.datanode.data.dir是元数据目录和数据块目录,注意这里用的是file:///协议,不是hdfs://

4.3 NameNode 格式化与启动验证

这里有个特别重要的操作顺序:第一次启动 HDFS 前,必须先格式化 NameNode。

hdfs namenode -format

格式化其实就是初始化 NameNode 的元数据目录,创建fsimage文件。操作时间很短,但有一点必须强调:格式化操作只有首次部署或者确认元数据没问题时才做,一个认真跑过业务的集群,随便格式化就等于删库跑路。所以很多老手在脚本里会加一个确认提示,防止手误。

格式化后启动:

start-dfs.sh

执行完你可以通过jps查看 Java 进程:

jps

伪分布式模式下你至少应该看到NameNodeDataNodeSecondaryNameNode三个进程。如果只有jps自己,那说明启动失败了,去/opt/hadoop/logs/hadoop-hadoop-namenode-*.log里找具体原因。

启动 HDFS 后,验证手段:

hdfs dfs -mkdir -p /user/hadoop hdfs dfs -put /etc/hosts /user/hadoop/ hdfs dfs -ls /user/hadoop

然后把 YARN 也启动起来:

start-yarn.sh

start-yarn.sh会拉起 ResourceManager 和 NodeManager,再次用jps验证,应该能看到四个进程(NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager,这里其实是五个)。

注意:上述在伪分布式下start-yarn.sh拉起的 NodeManager 可能与 DataNode 同机,是正常的。完整验证可以在浏览器打开http://localhost:9870,看到 NameNode 的 Web 界面,里面能查看 HDFS 的存储容量、存活节点数、文件块状态。YARN 的界面在http://localhost:8088

4.4 伪分布式模式下的常见坑

伪分布式部署看似简单,但有几个问题很容易出现。第一个是DataNode 起不来,这通常是因为dfs.datanode.data.dir指向的目录没有创建,或者权限不对。第二个是NameNode 的 Web 界面打不开,检查防火墙是不是把 9870 端口封了,我这边云服务器第一次部署经常遇到。

第三个比较隐蔽的是启动时可能会提示堆内存不足,因为 Hadoop 默认的 NameNode 堆内存只有 1G,如果你机器内存够大可以调大,后面讲生产配置时会细说。第四个是格式化失败,大概率原因是hadoop.tmp.dir目录下有上次部署残留的数据,需要把hadoop.tmp.dirdfs.namenode.name.dirdfs.datanode.data.dir三个目录全部清空,再重新格式化,不然会报Storage directory already exists之类的错误。

我在伪分布式模式下还遇到过一个问题:DataNode 启动后很快自动退出,查看日志提示There appears to be a gap in the transaction ID。这个的根源是 NameNode 元数据目录和 DataNode 数据目录不是同一次格式化生成的,你可能是先启动了 NameNode,然后再配好 DataNode 数据目录再启动,导致 NameNode 的clusterID和 DataNode 的不一致。解决办法就是清空 DataNode 数据目录,或者把记录在VERSION文件里的clusterID改成和 NameNode 一致,然后重启 DataNode。

5. 完全分布式集群搭建核心环节

单机伪分布式跑通之后,扩展成三节点集群就很顺畅了。这里我把最核心的配置和启动流程完整走一遍。

5.1 集群配置文件修改与分发

我上面说的三节点规划:node1是主节点,node2node3是数据节点。在node1上修改配置后,要把整个配置目录分发到node2node3

core-site.xml的修改相对简单:

<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node1:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop/tmp</value> </property> </configuration>

这里变化只有一处,localhost改成了node1。注意,node1必须能被所有节点解析。我习惯在/etc/hosts中静态绑定 IP 和主机名,而不是依赖 DNS,减少一个故障点。

hdfs-site.xml则要把副本数调回 3:

<configuration> <property> <name>dfs.replication</name> <value>3</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///opt/hadoop/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///opt/hadoop/data/datanode</value> </property> <property> <name>dfs.namenode.http-address</name> <value>0.0.0.0:9870</value> </property> <property> <name>dfs.permissions.enabled</name> <value>false</value> </property> </configuration>

这里加了一个dfs.permissions.enabled=false,我在测试环境这么开是为了省去权限麻烦。但生产环境千万别关,否则所有用户都能删 HDFS 文件,权限审计直接废掉。

YARN 的配置在yarn-site.xml

<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>node1</value> </property> <property> <name>yarn.nodemanager.env-whitelist</name> <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value> </property> </configuration>

yarn.nodemanager.aux-services这个参数特别容易漏掉,它的作用是让 NodeManager 能启动 MapReduce Shuffle 服务。如果不配置,MR 任务在 Shuffle 阶段会一直卡住,日志里报错却和这个参数毫无关系,排查起来非常痛苦。yarn.resourcemanager.hostname指定 ResourceManager 所在节点。还有一个yarn.nodemanager.env-whitelist,这个是让 NodeManager 在启动容器时保留JAVA_HOME等环境变量,不配置的话,某些 Spark 任务在 container 里会找不到 Java。

mapred-site.xml(原本叫mapred-site.xml.template,需要重命名):

<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.application.classpath</name> <value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value> </property> </configuration>

mapreduce.framework.name=yarn表示 MapReduce 作业提交到 YARN 上运行,如果不配这个,默认是 local 模式,作业只在提交节点本地跑,完全无法利用集群资源。mapreduce.application.classpath是因为 Hadoop 3.x 之后如果没有显式指定 classpath,作业提交时经常报找不到mapred-site.xml里的类。

最后要修改的是workers文件。在 Hadoop 3.x 中,这个文件名是workers(2.x 里叫slaves)。它告诉 Hadoop 哪些节点是 DataNode 和 NodeManager:

node1 node2 node3

注意:在完全分布式模式下,主节点node1是否参与数据存储,取决于你写不写进workers。我这边三节点集群让node1也参与存储,这样数据均衡和吞吐量更好。如果数据节点资源非常大、想隔离角色,可以不写node1

配置文件修改完成后,把整个etc/hadoop目录分发到node2node3

scp -r /opt/hadoop/hadoop/etc/hadoop node2:/opt/hadoop/hadoop/etc/ scp -r /opt/hadoop/hadoop/etc/hadoop node3:/opt/hadoop/hadoop/etc/

有个地方要注意:node2node3的 JDK 路径和 Hadoop 路径必须和node1完全一致,否则启动时找JAVA_HOMEHADOOP_HOME就会报路径不存在。我配了那么多集群,90% 的启动失败都是路径不一致,而不是配置语法错误。

5.2 集群启动顺序和验证

在完全分布式模式下,格式化 NameNode 只是在node1上执行,千万不要在每台节点上分别格式化,不然clusterID不一致,DataNode 全部拒绝连接。

hdfs namenode -format

格式化完成后启动 HDFS:

start-dfs.sh

脚本执行时会通过 SSH 远程拉起每个节点的 DataNode,最后输出各个节点的启动情况。然后启动 YARN:

start-yarn.sh

这时候在各节点上分别执行jps,你期望看到:

节点进程列表
node1NameNode、SecondaryNameNode、ResourceManager、NodeManager、DataNode
node2DataNode、NodeManager
node3DataNode、NodeManager

我见过很多人启动完start-dfs.sh后在主节点看到NameNodeSecondaryNameNode起来了,但 DataNode 迟迟不出现。原因绝大多数都是workers文件里的主机名不对,或者 SSH 免密没配全。执行start-dfs.sh时脚本会逐个 SSH 到workers列表里的节点,如果某个节点 SSH 不通,它只是打印一行警告,不会整体报错。

验证集群状态的命令:

hdfs dfsadmin -report

这个命令会列出所有 DataNode 的存储容量、剩余空间、最后心跳时间。正常节点状态应该是In Service,如果显示DECOMMISSIONEDNODE_EXPIRED,多半是网络通信或者心跳配置有问题。还可以执行:

hdfs dfsadmin -safemode get

如果输出Safe mode is OFF,说明集群可以正常读写。如果处于 safe mode,用hdfs dfsadmin -safemode leave强制退出,或者等它自动退出。

5.3 集群核心参数调优经验

集群能正常启动只是第一步,生产级集群还需要做内存和并发层面的调优。这里列几个我会重点关注的参数。

HDFS 端,最核心的是 NameNode 堆内存。默认值是 1G,但文件数量超过百万级后,NameNode 堆内存很快就扛不住。调整方式在hadoop-env.sh中设置:

export HADOOP_NAMENODE_OPTS="-Xms16g -Xmx16g"

对于千万级文件,16G堆是起步水平。同时注意dfs.namenode.handler.count,这个参数控制 NameNode 处理 RPC 请求的线程数,默认值是 10,文件操作频繁时建议调到 32 以上。计算方式大致是20 * log2(集群规模),三节点集群调到 32 就够了。

YARN 端,主要看yarn-site.xml里的内存调度配置:

<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>16384</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>8192</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>1024</value> </property>

这说明每台 NodeManager 能管理 16G 内存,单个容器最大申请 8G、最小申请 1G。这里有个容易踩的坑:yarn.nodemanager.resource.memory-mb不要配置成物理内存的 100%,要给操作系统、DataNode 和其他进程留至少 30% 的余量。我之前有台机器 32G 内存,直接配了 28G 给 YARN,结果 DataNode 频繁 GC,最后反而给 Namenode 挤崩了。

并发参数里,yarn.nodemanager.resource.cpu-vcores我一般配成物理核数减 1,留一个核给系统。yarn.scheduler.maximum-allocation-vcores则限制单个容器最多能拿多少核,防止一个吃 CPU 的任务把集群跑挂。

5.4 重启流程与平滑操作

在完全分布式集群上重启 Hadoop,一定要有顺序意识。正常顺序是:先停 YARN,再停 HDFS;启动时反过来,先启 HDFS,再启 YARN。顺序错了虽然不一定会直接报错,但会造成 ResourceManager 找不到 NameNode 地址、任务提交时超时等诡异问题。

# 停止 stop-yarn.sh stop-dfs.sh # 启动 start-dfs.sh start-yarn.sh

还有一个经验:改配置后不一定需要重启整个集群。比如只改了hdfs-site.xml的副本数,用hdfs dfsadmin -refreshNodes或者hdfs dfsadmin -refreshSuperUserGroupsConfiguration,很多参数能热刷新。但 YARN 的调度器参数改动,通常需要在 ResourceManager 界面点击 Active 节点页面里的Refresh Queues,或者执行:

yarn rmadmin -refreshQueues

这个操作不需要重启,能大幅减少集群停机时间。我维护的集群里,改队列配额、加用户权限,基本都是热刷新完成的,只有改yarn-site.xml里的基础参数才需要滚动重启 ResourceManager。

6. 常见问题与故障排查手册

这部分是我最想分享的。Hadoop 集群就是这样,能启动不等于能正常用,正常用不等于永远不出问题。我整理了一线运维中经常遇到的高频问题,每个都附带排查思路和解决方案。

6.1 启动类问题:DataNode 起不来/连不上 NameNode

现象jps看不到 DataNode 进程,或日志里反复出现Connection refused

排查步骤

先看日志,DataNode 日志默认在/opt/hadoop/logs/hadoop-hadoop-datanode-*.log。常见的三个原因:一是workers文件里的主机名写错了;二是dfs.datanode.data.dir对应的目录不存在或权限不足;三是 DataNode 启动时发现clusterID与 NameNode 不一致。

我用过的排查命令:

# 在主节点上查看 DataNode 是否有存活注册 hdfs dfsadmin -report # 在 DataNode 节点上查看日志 tail -n 50 tail -n 50 /opt/hadoop/logs/hadoop-hadoop-datanode-*.log # 直接查看注册信息 hdfs dfsadmin -printTopology

如果是clusterID不一致,日志里会有这么一句:Incompatible clusterIDs in ...。修复办法是:把 DataNode 的VERSION文件里的clusterID改成和 NameNode 的一致(文件路径在数据目录下current/VERSION),或者干脆清掉 DataNode 数据目录后重新初始化。

提示:如果集群已经写了数据,清空 DataNode 数据目录会导致这个节点上的所有块重新复制,在有副本的情况下能自动恢复,但复制过程会占用大量网络和磁盘 IO,生产环境要谨慎操作。

6.2 存储类问题:HDFS 写入失败/磁盘空间不足

现象hdfs dfs -putThere are X missing blocks或者No available replicas

这个报错我看到很多新手一脸懵。首先确认有没有活着的数据节点:

hdfs dfsadmin -report

如果 DataNode 全部 In Service,再看是不是磁盘满了。hdfs dfsadmin -report输出里每一行的DFS Used%能直接看出每个节点的磁盘占比。Hadoop 默认有一个阈值,当 DataNode 的磁盘使用率超过dfs.datanode.du.reserved时,这个节点不会再接受新的数据块写入。

还有一种隐蔽情况是block 损坏。用下面的命令检查:

hdfs fsck / -files -blocks -locations

如果fsck报告某个路径下有CORRUPT块,但你的副本数是 3,且确实有 3 个 DataNode,那大概率是某个节点上的磁盘有坏道或者文件被外部程序篡改了。这时可以先看具体坏块位置,通常有两种处理:一是找到对应 DataNode,删掉坏块文件,让 HDFS 从其他副本重新复制;二是如果副本本来就只剩一个,那就得从快照或者备份里恢复了。生产环境建议开启 HDFS 快照定期备份。

6.3 性能类问题:MapReduce 任务卡住/运行极慢

MapReduce 任务跑得慢,不一定都是 Hadoop 配置的问题。我从排查顺位来说:

  1. 看 YARN 资源够不够:打开 ResourceManager 的 Web 界面,看集群可用资源。如果有大量任务排队,可能是yarn.scheduler.maximum-allocation-mb配小了,单个任务申请不到足够的容器。

  2. 看 Map 阶段是否卡在 Shuffle:如果 Reduce 进度一直停在 33% 左右,通常是mapreduce.reduce.shuffle.parallelcopies配置太低,导致 Reduce 拉取 Map 输出的并发度不够。可以适当调高,比如从默认的 5 调到 20。

  3. 看数据倾斜:如果某些 Reduce 处理的数据量明显多于其他,典型特征是有几个 task 跑得特别慢,而大部分已经完成。这时候要检查 Map 输出是不是有热点 key。解决方案可以在业务侧做二次 Key 加盐,或者在 Hive 里开启hive.groupby.skewindata=true

  4. 看网络和磁盘:如果某个节点上的 Map 任务普遍比别的节点慢,用df -hiostat看看是不是磁盘 IO 满了,或者网络有人跑了大流量任务抢带宽。

还有个小细节:Hadoop 默认的压缩配置很保守,如果任务中间结果很大,可以在mapred-site.xml里开启压缩:

<property> <name>mapreduce.map.output.compress</name> <value>true</value> </property> <property> <name>mapreduce.map.output.compress.codec</name> <value>org.apache.hadoop.io.compress.SnappyCodec</value> </property>

这一步对 Shuffle 阶段可以减少 60% 以上的网络传输量,尤其是中间数据大的任务,效果立竿见影。

6.4 版本升级与 3.5.0 新版本参考

最后说下和热词相关的话题:Apache Hadoop 3.5.0。如果你的集群还没有上线,或者你还在规划阶段,完全可以直接用 3.5.0 在新环境里做验证,但如果是存量生产集群,我建议先了解 3.5.0 和 3.3.3 的差异,再评估迁移价值。

3.5.0 有几个值得关注的改进点:

  • HDFS 支持了更灵活的 EC 策略,能够在线调整纠删码策略的写入带宽,对冷数据存储场景更友好。
  • YARN 的 Federation 功能进一步成熟,能在一个集群里通过 Router 管理多个子集群,适合超大规模部署。
  • 更多的 Java 优化和依赖清理,包体积更小,启动更快。
  • 对 S3A 连接器做了性能优化,如果你使用公有云对象存储作为 HDFS 的补充,这条会比较实用。

但升级之前必须做一件事:查看 HDFS 的升级兼容文档。Hadoop 3.x 内部的 RPC 协议和存储格式不一定保证向后兼容,老集群直接升级到 3.5.0,可能出现 EditLog 格式不兼容导致无法回滚的情况。我见过一个团队从 3.2 直接升 3.5,升完发现 Hive 的 metastore 还在用旧版 Hadoop 客户端,协议不兼容,全部查询失败,花了整整两天才把版本回退。

如果你确实要升级,我建议的路径是:先开一个测试集群,从 3.3.3 升级到 3.5.0,跑完整业务回归,再通过hdfs upgrade滚动升级或者用新集群做数据迁移,确保万无一失。

7. 一些小建议和实际体验

部署 Hadoop 这件事,做多了你会发现真正的难点不在安装本身,而在对整个系统的理解。hadoop-3.3.3.tar.gz只是一个压缩包,但解压之后,你面对的是一个需要精心调教的分布式系统。

我个人在实操中最深的体会是:配置参数一定要有目的性地去改,不要照搬网上的模板。每台机器硬件不同、业务不同,默认配置只能保证能跑,没法保证跑得好。比如dfs.replication,默认是 3,单机测试必须改成 1,但如果我们只是拿它跑实验性任务,副本数设为 2 就够了,省下的存储空间很可观。

最后分享一个小技巧,就是一定把配置变更纳入版本管理。我在团队里推广的是,把hadoop/etc/hadoop整个目录放进 Git 仓库,每次改配置都 commit 一次。等出了问题,能清楚地看到哪次改动导致了集群异常,而不是靠翻聊天记录去猜。这套流程看似简单,但真正坚持下来的人不多,可它确实能让你在维护集群时省下大量时间。建议所有搞 Hadoop 的朋友都试一下,养成习惯后你会回来感谢我的。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询