ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hadoop完全分布式集群从零搭建实战:避开这些坑一次成功

Hadoop完全分布式集群从零搭建实战:避开这些坑一次成功 动手搭建过 Hadoop 完全分布式集群的人应该都有同感看教程觉得“就这几步”真到自己从零开始配各种莫名其妙的问题能把人折腾到怀疑人生。尤其是零基础阶段连“伪分布式”和“完全分布式”的区别都还没彻底搞清就被一堆 XML 配置文件和进程启动顺序砸懵了。这篇文章我打算换个思路不堆概念直接按我实际搭建时的操作顺序来走。目标很明确用最少的基础依赖在虚拟机或云服务器上从零拉起一个真正可用的 Hadoop 完全分布式集群跑通 HDFS 和 YARN 的核心流程。整个过程我会把每一步“为什么这么做”也讲清楚而不是只丢给你一堆复制粘贴的命令。这篇内容适合刚学完 Linux 基础、准备进入大数据方向或者在公司里需要自己搭一套测试集群的开发者参考。跟着做完你会对 NameNode、DataNode、ResourceManager、NodeManager 这几个角色之间的关系有非常直观的理解。1. 搭建前的整体思路与规划1.1 完全分布式到底“完全”在哪很多初学者会混淆伪分布式和完全分布式。伪分布式是在一台机器上同时跑所有守护进程NameNode、DataNode、ResourceManager 都是本地进程主要用于功能验证而完全分布式是把这些角色拆分到多台物理或虚拟节点上各自承担独立职责这才贴近生产环境的部署形态。我们这次规划使用三台节点master运行 NameNode 和 ResourceManager负责管理元数据和全局资源调度slave01 / slave02运行 DataNode 和 NodeManager负责实际的数据存储和计算任务执行从进程分布可以看出Hadoop 的架构设计就是把“管理”和“存储/计算”分离所以 master 节点的配置不需要太高反而是 slave 节点承担了主要的数据读写压力。1.2 版本选择与为什么是这套组合Hadoop 的版本选择是个老话题。我建议零基础用户直接选择 Hadoop 3.3.x 版本搭配 JDK 1.8。理由有三点第一Hadoop 3.x 相比 2.x 修复了大量 Bug而且默认支持 Erasure Coding 和多个 NameNode 的配置方式更灵活第二很多网上教程基于 Hadoop 2.x 编写配置项名称和默认值与 3.x 有不少差异抄作业时容易踩坑第三JDK 1.8 是 Hadoop 官方长期验证的版本虽然新版本也支持 JDK 11但对初学者来说没必要在 Java 版本上给自己增加变量。Linux 发行版我建议使用 CentOS 7.9 或者 Ubuntu 20.04/22.04。两者的核心配置思路完全一致区别只在于部分命令和目录结构。为了统一讲解我以 CentOS 7.9 为例如果你用 Ubuntu把yum换成apt、firewall-cmd换成ufw即可。1.3 用表格理清三台机器的基础分工在开始敲命令之前先把规划固化下来。我每次搭建都会先做一张表格后面配置时就不会乱节点名主机名IP 示例运行角色内存建议masterhadoop-master192.168.10.10NameNode、ResourceManager2GBslave01hadoop-slave01192.168.10.11DataNode、NodeManager2GBslave02hadoop-slave02192.168.10.12DataNode、NodeManager2GB这里的 IP 你可以根据自己虚拟机或云服务器的实际网络来调整但三台机器必须能互相 ping 通。我见过不少人在配置阶段卡壳最后排查发现是防火墙把端口拦了所以网络连通性测试一定要在第一阶段就做掉。注意生产环境或云服务器上安全组规则和防火墙策略请按实际要求开放端口。本地虚拟机学习场景中最简单的方式是直接关闭 firewalld减少干扰。2. 基础环境配置三台机器统一处理2.1 修改主机名与 hosts 映射主机名规划很重要因为 Hadoop 集群内部的节点互相通信时依赖的是主机名而不是 IP。如果主机名不对后续启动 HDFS 时经常会出现UnknownHostException这种莫名其妙的问题。在三台机器上分别执行# master 节点 hostnamectl set-hostname hadoop-master # slave01 节点 hostnamectl set-hostname hadoop-slave01 # slave02 节点 hostnamectl set-hostname hadoop-slave02然后修改三台机器的/etc/hosts文件加入互相的映射关系cat /etc/hosts EOF 192.168.10.10 hadoop-master 192.168.10.11 hadoop-slave01 192.168.10.12 hadoop-slave02 EOF这里一定要三台机器都配置同一份 hosts 内容。我见过有人只在 master 上配了 hosts结果 slave 节点互相访问时解析不了主机名DataNode 之间做数据块复制时直接报错。2.2 配置 SSH 免密登录Hadoop 的守护进程启动时master 节点需要通过 SSH 连接到所有 slave 节点远程拉起 DataNode 和 NodeManager 进程。如果不配免密每次启动集群都要输入密码那是完全不可接受的。在 master 节点上生成密钥对ssh-keygen -t rsa -b 4096 -P -f ~/.ssh/id_rsa然后把公钥分发到三台机器包括 master 自己ssh-copy-id hadoop-master ssh-copy-id hadoop-slave01 ssh-copy-id hadoop-slave02执行过程中会要求输入一次对方机器的 root 密码之后就再也不需要了。验证方式很简单ssh hadoop-slave01 hostname能直接输出hadoop-slave01就说明免密配置成功。这里我要专门提一个坑有些教程会让在每台机器上都生成密钥再互相拷贝这样可以实现“全互联”免密。实际上 Hadoop 只需要 master 能免密登录所有节点就够了slave 节点之间不需要互信。重复配置不仅没必要而且容易在分发公钥时搞混。2.3 安装 JDK 1.8 并配置环境变量Hadoop 本身是用 Java 写的所以 JDK 是三台机器都必须装的基础软件。我建议使用 Oracle JDK 8 或 OpenJDK 8不要在这上面追求新版本。yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel安装完成后找到 Java 的安装路径which java ls -l $(which java)通常在/usr/lib/jvm/java-1.8.0-openjdk-xxx目录下。把这个路径写入/etc/profilecat /etc/profile EOF export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.xxx export PATH$PATH:$JAVA_HOME/bin EOF source /etc/profile java -version看到类似openjdk version 1.8.0_xxx的输出就说明 JDK 配置完成。提示三台机器都要安装 JDK不要只在 master 上装完就以为完事了。DataNode 和 NodeManager 同样需要 JVM 来运行。3. Hadoop 安装与核心配置文件解析3.1 下载解压与目录规划到 Hadoop 官网下载二进制包或者直接用国内镜像源下载 3.3.x 版本。我只在 master 节点下载配置完成后通过 scp 分发到 slave 节点保证版本完全一致。cd /opt wget https://mirrors.xxx/apache/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz tar -zxvf hadoop-3.3.6.tar.gz mv hadoop-3.3.6 /usr/local/hadoop然后配置 Hadoop 的环境变量cat /etc/profile EOF export HADOOP_HOME/usr/local/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop EOF source /etc/profile目录规划上我习惯把临时文件和数据存储目录单独放在/data/hadoop下不跟安装目录混在一起。这样后续要清理数据、重新格式化时只需清空一个目录不用动安装目录的配置。3.2 修改 hadoop-env.sh 中的 Java 路径这是最容易忽略的配置。虽然我们已经把JAVA_HOME写进了/etc/profile但 Hadoop 的守护进程脚本在启动时不一定能正确加载用户环境变量所以最稳妥的做法是在hadoop-env.sh里显式指定vim /usr/local/hadoop/etc/hadoop/hadoop-env.sh # 修改为 export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.xxx不配这个启动时大概率会报JAVA_HOME is not set或者Error: JAVA_HOME is not set而且这个错不会出现在日志文件里只在控制台一闪而过非常坑。3.3 核心配置文件 core-site.xmlconfiguration property namefs.defaultFS/name valuehdfs://hadoop-master:9820/value /property property namehadoop.tmp.dir/name value/data/hadoop/tmp/value /property /configurationfs.defaultFS指定了 HDFS 的访问入口hadoop.tmp.dir是 NameNode 和 DataNode 存储元数据和数据块的根目录。这个目录必须提前创建而且三台机器上的路径要保持一致mkdir -p /data/hadoop/tmp3.4 HDFS 配置文件 hdfs-site.xmlconfiguration property namedfs.namenode.name.dir/name valuefile:///data/hadoop/namenode/value /property property namedfs.datanode.data.dir/name valuefile:///data/hadoop/datanode/value /property property namedfs.replication/name value2/value /property /configurationdfs.namenode.name.dir是 NameNode 的元数据存储路径dfs.datanode.data.dir是数据块实际存放路径。这两个目录也要提前创建。dfs.replication这里设置成 2因为我们的集群只有两个 DataNode。如果你按默认值 3 来配置那么第二份副本写完后第三份副本会因为找不到节点而一直处于等待状态虽然不会直接报错但你在 Web 界面上会看到某些数据块一直显示Under-Replicated。3.5 YARN 配置文件 mapred-site.xml 和 yarn-site.xmlmapred-site.xml 指定 MapReduce 运行在 YARN 之上configuration property namemapreduce.framework.name/name valueyarn/value /property /configurationyarn-site.xml 指定 ResourceManager 所在节点和 NodeManager 的资源分配方式configuration property nameyarn.resourcemanager.hostname/name valuehadoop-master/value /property property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.nodemanager.aux-services.mapreduce_shuffle.class/name valueorg.apache.hadoop.mapred.ShuffleHandler/value /property /configurationyarn.nodemanager.aux-services是容易被漏掉的配置。MapReduce 任务在 Shuffle 阶段需要 NodeManager 提供一个辅助服务来传输中间数据如果不配置这个参数任务会在 Shuffle 阶段卡死或者直接失败。3.6 workers 文件与分发集群在 Hadoop 3.x 中不再叫 slaves 文件而是workers路径在/usr/local/hadoop/etc/hadoop/workers。写入两个 slave 节点的主机名cat /usr/local/hadoop/etc/hadoop/workers EOF hadoop-slave01 hadoop-slave02 EOF这个文件的作用是告诉 master 节点启动时要去哪些机器上拉起 DataNode 和 NodeManager。然后通过 scp 把整个 Hadoop 目录分发到两台 slave 节点scp -r /usr/local/hadoop hadoop-slave01:/usr/local/ scp -r /usr/local/hadoop hadoop-slave02:/usr/local/注意/etc/profile的环境变量配置也要同步到 slave 节点否则在 slave 上直接执行hdfs dfs命令时找不到命令。4. 启动集群格式化的正确姿势与容易踩的坑4.1 启动前必须完成的目录初始化在所有配置完成后第一件正事是在 master 节点上执行 NameNode 的格式化hdfs namenode -format这一步的作用是生成 NameNode 所需的元数据文件包括fsimage和edits日志。成功执行后会在控制台看到Storage directory ... has been successfully formatted这样的提示。这里有一个新手最容易犯的错误反复格式化 NameNode导致 DataNode 和 NameNode 之间的clusterID不一致启动时 DataNode 一直在日志里报错但就是注册不上。为什么会出现这个问题因为格式化会清空 NameNode 的元数据并生成一个新的 clusterID而已经启动过的 DataNode 在自己的数据目录里存了旧的 clusterID。两边对不上DataNode 就拒绝工作。解决办法有两条路一条是在第一次格式化之前确保所有节点的/data/hadoop目录都是空的然后启动整个集群之后不再轻易格式化另一条是如果确实需要重新格式化必须同时清空所有节点的/data/hadoop/namenode和/data/hadoop/datanode目录保持两边都从零开始。注意格式化操作永远只在 master 节点上执行一次。把这个命令当成“集群安装完毕后的唯一一次初始化动作”而不是“集群出问题了就格式化一下”。4.2 启动 HDFS 与 YARN 的正确顺序格式化完成后一次性启动所有角色start-dfs.sh start-yarn.sh为什么推荐分成两步因为分开执行可以更清楚地定位问题。start-dfs.sh会在 master 启动 NameNode并根据 workers 文件远程启动各 slave 节点上的 DataNode。start-yarn.sh则会在 master 启动 ResourceManager并远程启动 NodeManager。执行完后用jps命令检查各节点的进程情况。master 节点上应该看到NameNodeResourceManagerSecondaryNameNodeHadoop 3.x 默认会自动启动slave01 和 slave02 上应该看到DataNodeNodeManagerjps是 JDK 自带的小工具专门用来查看 Java 进程。如果发现某个角色没有出现第一步先看对应日志文件日志路径默认在/usr/local/hadoop/logs下文件名格式是hadoop-用户名-角色-主机名.log。4.3 Web 界面验证集群状态HDFS 的 Web 界面默认端口是 9870访问http://hadoop-master:9870能看到 NameNode 的管理界面。这里有几个关键信息值得看Configured Capacity集群总存储容量DFS Used已使用的存储空间Live Nodes存活的 DataNode 数量必须等于 2YARN 的 Web 界面默认端口是 8088访问http://hadoop-master:8088能看到 ResourceManager 的管理界面。重点看 Active Nodes 数量是否等于 2。我在实际搭建中遇到过一种情况jps显示 DataNode 进程存在但 Web 界面上 Live Nodes 显示只有 1 个。这种多半是另一个 DataNode 的日志里报了clusterID不匹配的问题处理方法就是我上面说的清空目录后重新初始化整个集群。4.4 用实际任务跑一遍集群进程都起来了不代表集群真能干活我习惯用一个最简单的 MapReduce 任务来验证# 创建测试目录 hdfs dfs -mkdir -p /test/input # 生成测试文件 echo hello hadoop /tmp/test.txt hdfs dfs -put /tmp/test.txt /test/input/ # 运行官方自带的 WordCount 示例 hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /test/input /test/output # 查看结果 hdfs dfs -cat /test/output/part-r-00000正常情况下输出结果里能看到hadoop 1和hello 1这样的统计结果。这个过程中你可以打开 YARN 的 Web 界面观察 Application 从 SUBMITTED 到 RUNNING 再到 FINISHED 的状态变化这比看任何文档都更能帮助你理解 YARN 的任务调度机制。执行完后再跑一次同样的命令会报错提示/test/output已存在。这是 HDFS 的特性——输出目录不允许自动覆盖可以先用下面的命令删除输出目录再重新执行hdfs dfs -rm -r /test/output5. 常见问题速查表与排查思路5.1 按症状快速定位问题我在帮人排查 Hadoop 集群问题时发现大部分故障都能归入下面几类。整理成表格方便你对照排查症状可能原因排查思路JAVA_HOME is not sethadoop-env.sh 未配置 Java 路径检查 hadoop-env.sh 中的 JAVA_HOME 是否指向正确目录DataNode 无法启动报 clusterID 不一致重复格式化 NameNode清空所有节点 namenode/datanode 目录后重新初始化start-dfs.sh卡住不动SSH 免密未配置成功手动执行ssh hadoop-slave01验证免密是否生效Web 界面打不开防火墙未放行端口检查 9870 和 8088 端口是否被防火墙拦截任务提交后一直 ACCEPTEDNodeManager 未启动或资源不足检查 slave 节点的 NodeManager 进程和可用内存HDFS 写入速度极慢副本数设置过大于节点数检查 dfs.replication 是否大于 DataNode 数量终端找不到hdfs命令环境变量未配置或未生效执行source /etc/profile并检查 PATH5.2 虚拟机搭建中的两个特殊注意点如果你用的是 VMware 或 VirtualBox 搭虚拟机有两个配置需要额外留意。第一个是虚拟机的 NAT 网络模式。NAT 模式下多台虚拟机之间能互相通信但如果你把 IP 设置为 DHCP 动态分配重启后 IP 会变化导致 hosts 文件里配置的映射全部失效。学习阶段最稳妥的做法是手动指定静态 IP三台机器保持在同一个网段内。第二个是内存分配。每台虚拟机如果只分 512MB 或 1GB 内存Java 进程很容易因为内存不足被系统自动杀死。java 进程被 OOM Killer 干掉后jps里什么都看不到日志里也未必有明显报错。我给这套三节点集群的底线建议是每台虚拟机至少 2GB 内存master 节点如果条件允许可以给到 3GB。5.3 日志文件是我排查问题的第一入口在 Hadoop 的世界里不要靠猜来排查问题日志永远是最直接的答案。我自己的排查顺序很固定先看~/logs目录下的日志文件重点看 WARN 和 ERROR 级别的记录。如果日志里没有明显异常再去看进程是否存在用jps验证。最后检查端口监听状态比如netstat -tlnp | grep 9870确认对应的 Web 端口是否正常。很多时候新手搞不定问题不是问题本身有多复杂而是没养成“先看日志再动手”的习惯。举例来说DataNode 启动失败时日志文件最后几行通常会直接告诉你具体原因是目录权限不对、磁盘空间不足还是 clusterID 不匹配。这些信息比在群里问人更准确。6. 从零到完全分布式的心得我搭过很多次 Hadoop 集群从最早跟着教程一步步敲命令的懵懂到现在能快速定位问题有个很深的体会这套系统之所以让初学者觉得难并不是配置有多复杂而是整个过程中的“隐式依赖”太多了。比如 SSH 免密是 start-dfs.sh 脚本能远程启动 DataNode 的前提hosts 映射是节点间通信的基石clusterID 一致性又是 DataNode 能注册到 NameNode 的条件。这些前置条件没人提醒出了问题时又不好排查就非常打击信心。如果你正在搭建过程中卡住了我的建议是别硬熬。把报错信息原封不动复制到搜索引擎里大概率能找到前人的解决记录。如果在云服务器上搭建别忘了检查安全组规则在本地虚拟机搭建就优先检查防火墙状态。环境问题解决了配置本身反而是花时间最少的部分。另外说个小技巧所有配置文件都改完后记得在 master 节点上执行一次source /etc/profile然后通过 SSH 登录到 slave 节点也验证一下hdfs命令是否可用。很多时候你在 master 上操作正常但远程启动时 slave 节点上找不到命令就是因为环境变量没有传播过去。最后想补一句如果你打算在这个集群上继续深入学习下一步可以试试安装 ZooKeeper为 HDFS HA 高可用做铺垫。完全分布式搭建是第一步但真正的挑战在于如何让集群更稳定、更可靠这一路踩坑攒下来的经验才是最有价值的东西。
返回列表