ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

手动搭建 Hadoop 集群:从零到跑通 WordCount 的完整实战指南

手动搭建 Hadoop 集群:从零到跑通 WordCount 的完整实战指南 如果你问我大数据入门最绕不开的一步是什么我的答案是自己动手搭一套 Hadoop 集群。这个结论听起来有点“复古”——现在云上 Hadoop、CDH、Ambari 一键部署到处都是为什么还要自己受这个罪我自己的经历是头一回搭集群跟着网上的教程敲了一整天命令最后卡在 DataNode 起不来格式化、删目录、再格式化折腾到后半夜才发现问题是 /etc/hosts 里主机名没对上。后来带新人也发现了一个规律一上来就靠一键部署的同学遇到问题基本都懵而认认真真从 JDK、SSH、配置文件手搭过一遍的人后面排查问题上手特别快。这篇文章不是一个“照着敲就能跑通”的命令流水账而是把集群搭建背后的规划思路、版本选型逻辑、配置文件里每个参数的含义、格式化为什么只能做一次、进程起不来该怎么查一次讲清楚。文章以一个主节点加两个从节点的三机集群为例从环境规划一直讲到跑通第一个 WordCount全程都是可以直接复用的实操经验。适合刚学完 Hadoop 理论准备动手实操的初学者也适合要搭测试环境或者做课程实验、毕业设计的老手快速避坑。1. 动手之前的规划搞清集群给谁用、怎么用1.1 为什么我坚持让人手动搭一遍集群有很多朋友问过我既然有 Ambari、Cloudera Manager 这种工具为什么不直接用我工作中确实也用这些工具做大规模集群管理但学习阶段我强烈建议手动搭一遍。原因很简单Hadoop 集群的核心是一个分布式系统节点之间怎么通信、主节点挂了怎么办、数据放在哪、资源怎么调度这些问题的答案全部藏在安装和配置文件里。用工具自动部署等于把最关键的分布式系统原理封装成了一个黑盒出问题以后根本不知道从哪里下手。我自己带人时做过一个对比让新人 A 用 Ambari 装了一套三节点集群让新人 B 手动安装。两周后丢一个同样的故障场景给两个人——DataNode 全部显示 dead。A 的第一反应是去翻 Ambari 的告警页面点重启按钮B 则会先去查 NameNode 日志、看 clusterID、检查数据目录权限。这就是手动搭建带来的排查思维差异。所以这篇文章不是“反工具”而是强调先理解再谈自动化。1.2 版本选型Hadoop 3.3.x 与 JDK 的搭配逻辑版本选型是搭建前第一个隐形坑。很多教程还在用 Hadoop 2.7.x JDK 7那套组合放到今天既不安全也不符合生产环境主流。Hadoop 3.2 之后对 JDK 11 就有了很好的支持3.3.x 系列是当前最常用的稳定版本线我用的具体版本是 Hadoop 3.3.6配合 JDK 1.88u202。JDK 8 虽然“老”但在 Hadoop 生态里依然是最稳的遇到问题网上的经验帖也最多。如果你没有特殊需求认准 JDK 8 Hadoop 3.3.x 这个组合基本不会出错。这里多说一句Hadoop 不同版本对 JDK 的兼容要求差异很大Hadoop 2.x 只能用 JDK 7/8Hadoop 3.3.x 才能同时支持 JDK 8 和 JDK 11。你后续如果要在这个集群上继续装 Hive、Spark、FlinkJDK 版本会直接影响这些组件能不能跑起来。比如你装的是新版 Spark 3.5它就明确要求 JDK 8/11/17但如果你的 Hadoop 是 2.x 版本又要被迫降回 JDK 8。所以选型阶段把整个生态链的版本一起规划能省掉后面数不清的坑。1.3 三节点规划主节点和从节点怎么分工生产环境为了高可用NameNode 和 ResourceManager 通常都要做 HA 双活但学习阶段完全没必要上那么重的架构。最合理的入门配置是三台机器一台作为主节点跑 NameNode 和 ResourceManager两台作为从节点跑 DataNode 和 NodeManager。NameNode 是 HDFS 的“大脑”ResourceManager 是 YARN 的“大脑”这两个放同一台机器上没有问题。数据节点则分布到另外两台机器上这样上传文件时才能真正看到副本机制的分发效果。三台机器的资源要求也不需要多高每台 2 核 4G 内存、40G 磁盘就够入门实验了。如果你用的是虚拟机或者 Docker 环境注意给主节点多留一点内存因为 NameNode 和 ResourceManager 都会常驻内存两台从节点内存小于 2G 跑 WordCount 会很吃力容易触发容器被 OOM Killer 干掉的问题。如果只是练习伪分布式一台机器也能跑但真正理解集群副本分布、数据分块这些机制还是必须上多节点。操作系统方面CentOS 7、Rocky Linux、Ubuntu Server 都可以。下面的操作我以 CentOS/Rocky 风格为例Ubuntu 的话把yum install换成apt install即可其他步骤基本通用。2. 基础环境配置主机名、用户、SSH 免密与防火墙2.1 统一用户和目录让三台机器有“共同语言”我见过很多新手直接拿 root 账号跑 Hadoop当时觉得没问题后来配置文件权限一乱日志都看不懂。规范做法是创建专用用户和规划目录。以下操作在三台机器上都执行一遍useradd -m hadoop passwd hadoop su - hadoopHadoop 的所有软件和数据目录都放在这个用户的家目录下。我的习惯是建三个目录/home/hadoop/software放源码包和解压后的程序/home/hadoop/data放 NameNode 元数据和 DataNode 数据/home/hadoop/logs放运行日志。目录分离最大的好处是升级 Hadoop 版本时只需要替换 software 目录里的程序数据不用动排查问题时日志集中在一个地方不用到处翻。如果你把数据默认放在/tmp下系统重启可能直接把元数据清空后面会专门讲这个坑。2.2 hosts 映射主机名通信是集群稳定的地基这是我在第一次搭建时栽过跟头的地方。Hadoop 集群内部是靠主机名互相通信的如果你不配置 hosts节点之间解析不到对方就会出现 NameNode 起了、DataNode 也起了但 DataNode 一直显示 dead 的情况。三台机器的/etc/hosts都要加上同样的一段映射192.168.1.101 node01 192.168.1.102 node02 192.168.1.103 node03每台机器的主机名也要和 hosts 保持一致。用hostnamectl set-hostname node01这样的命令分别设置然后用hostname命令验证。这一步不要图省事想跳过Hadoop 的很多组件在启动时会做正反解析校验主机名映射不一致或缺少映射会让你在启动阶段遇到一些非常无语的报错。2.3 SSH 免密登录从主节点到所有节点一把梭Hadoop 通过脚本起停守护进程时需要主节点远程登录到每台机器上执行命令。如果没有配置免密每次start-dfs.sh都会要求你输密码分布式环境下还经常出现卡在等待输入的地方。配置方式是只在主节点生成密钥对然后把公钥分发到所有节点包括主节点自己su - hadoop ssh-keygen -t rsa -P -f ~/.ssh/id_rsa ssh-copy-id node01 ssh-copy-id node02 ssh-copy-id node03-P 表示密钥口令为空。分批分发完成后在主节点上执行ssh node01、ssh node02、ssh node03各试一遍如果能不输入密码直接登进去说明配置成功。这里有个我踩过的坑生成密钥对时如果用的是 root 用户再切到 hadoop 用户去操作会因为/home/hadoop/.ssh目录的属主不对导致免密失效。所以整个 SSH 配置必须在 hadoop 用户下完成不要切换用户。2.4 防火墙和 SELinux默认关闭能省掉 80% 的怪问题集群搭建阶段我的建议是把防火墙直接关掉先把功能跑通后续再按安全要求精细化放行端口。在 CentOS/Rocky 上执行systemctl stop firewalld systemctl disable firewalld还要检查 SELinux 的状态用getenforce命令看。如果是Enforcing建议临时改为Permissive并修改/etc/selinux/config永久生效。SELinux 对文件访问权限有强制约束Hadoop 的守护进程如果在读写数据目录时被 SELinux 拦截日志里往往只显示 Permission denied非常难排查。有人会杠“生产环境不推荐关防火墙”这个说法没错但那是运维安全和网络隔离策略的问题不是一个入门集群该在搭建阶段就纠结的事。先把集群跑起来再在更上一层的网络安全策略里控制端口才是务实的路线。3. 核心配置文件逐个拆解参数背后的逻辑比记路径更重要三台机器的/etc/hosts配好之后下一步是在主节点上解压 Hadoop可以到 Hadoop 官网或清华镜像站下载hadoop-3.3.6.tar.gztar -zxvf hadoop-3.3.6.tar.gz -C /usr/local/ mv /usr/local/hadoop-3.3.6 /usr/local/hadoop chown -R hadoop:hadoop /usr/local/hadoop之后所有配置都在/usr/local/hadoop/etc/hadoop/目录里。我强烈建议配一个文件打开一个文件不要直接复制网上的“完整配置”粘贴进去因为一旦跑不起来你根本不知道是哪段配置写错了。下面逐个来。3.1 core-site.xml默认文件系统与临时目录core-site.xml是 Hadoop 的全局配置最重要的就是默认文件系统地址和临时目录。NameNode 的 RPC 端口在 Hadoop 3.x 里默认是9820千万不要再写 2.x 时代记忆里的9000否则客户端连接会一直超时。我的配置如下configuration property namefs.defaultFS/name valuehdfs://node01:9820/value /property property namehadoop.tmp.dir/name value/home/hadoop/data/tmp/value /property /configurationfs.defaultFS决定了客户端操作 hdfs 时默认连接的主节点是谁。这里写主机名node01而不是 IP是为了配合 hosts 映射做内部解析。hadoop.tmp.dir这个参数非常关键NameNode 和 DataNode 的默认数据目录都基于它生成。很多人习惯不配置它用系统默认的/tmp/hadoop-${user}结果系统定期清理 /tmp 目录后NameNode 元数据全没了整个集群直接“失忆”。我是一个吃过这个亏的人必须强调把这个目录指到家目录下独立的数据目录里是最好的习惯。3.2 hdfs-site.xml副本数、NameNode 目录与 DataNode 目录HDFS 里副本数是所有新手最容易迷惑的参数。默认是 3但我们这里只有两个从节点如果保持 3 会一直出现副本数不足的告警虽然不影响写入但看着心烦。所以我把副本数设为 2configuration property namedfs.replication/name value2/value /property property namedfs.namenode.name.dir/name valuefile:///home/hadoop/data/namenode/value /property property namedfs.datanode.data.dir/name valuefile:///home/hadoop/data/datanode/value /property property namedfs.namenode.secondary.http-address/name valuenode01:9868/value /property /configurationdfs.namenode.name.dir和dfs.datanode.data.dir分别指定了元数据目录和真实数据块的存储目录。显式指定它们的目的同样是避免落到默认的 tmp 目录。实际上 namenode 的 name.dir 支持写成逗号分隔的多个目录相当于把元数据同步备份多份生产环境会挂两块盘各存一份学习环境没必要这么搞但也别直接省掉这个参数。副本数dfs.replication配置的是每个数据块在所有 DataNode 上保存几份。如果副本数大于 DataNode 数量集群显示健康状态时会出现Replication factor required: 2, actual: 1之类的告警不影响使用但不利于你观察真正的健康度。3.3 yarn-site.xmlResourceManager 与 NodeManager 的协作YARN 是 Hadoop 的资源调度层负责给计算任务分配内存和 CPU。yarn-site.xml里两个必须配的参数是yarn.resourcemanager.hostname和yarn.nodemanager.aux-servicesconfiguration property nameyarn.resourcemanager.hostname/name valuenode01/value /property property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property /configurationyarn.resourcemanager.hostname告诉所有 NodeManager 去哪里找 ResourceManager。yarn.nodemanager.aux-services则是 YARN 中一个非常容易漏掉的参数它的作用是把 MapReduce 程序运行过程中产生的 shuffle 数据传输服务注册到 NodeManager 上。如果漏配这个参数YARN 集群能正常起但提交 MapReduce 任务会直接失败日志里提示找不到mapreduce_shuffle。我当时就在这上面卡了半个多小时因为两个主进程都活着、Web UI 也正常光看表面根本想不到是辅助服务缺失的问题。3.4 mapred-site.xml让 MapReduce 跑在 YARN 上Hadoop 3.x 的mapred-site.xml已经不需要复制模板直接编辑即可。这个文件的核心配置只有一项configuration property namemapreduce.framework.name/name valueyarn/value /property /configurationmapreduce.framework.name决定了 MapReduce 任务用什么方式运行。如果不配默认值是local意思是所有任务都在本地进程里串行执行完全用不到 YARN 集群的资源管理能力。很多教材把这一步省略了导致新手误以为 Hadoop 集群只包含 HDFS完全没有 YARN 的概念。这里把计算框架切到 yarn就是把“计算”和“资源”这两层绑定起来的关键动作。等到以后学 Spark 时你会发现Spark 也可以选择跑在 YARN 上原理是一模一样的。3.5 hadoop-env.sh 与 workers容易被忽略的两个文件hadoop-env.sh里有一行必须修改JAVA_HOME。虽然这台机器上/etc/profile里配了 JAVA_HOME但 Hadoop 的启动脚本不会自动读取登录 shell 的环境变量。直接把 JAVA_HOME 写死在环境脚本里是最可靠的方式export JAVA_HOME/usr/local/jdk8然后是workers文件。这个文件名在 Hadoop 3.x 里叫workers在 2.x 里叫slaves作用是声明哪些节点是 DataNode 和 NodeManager。内容非常简单每行写一个主机名node01 node02 node03注意这个文件只在主节点上配置DataNode 节点上的 Hadoop 配置可以完全从主节点同步过去。同步方式可以用scp也可以用 rsync关键是同步后要检查从节点上的配置文件和主节点一致。我的做法是把主节点etc/hadoop/下的文件直接覆盖到所有从节点的相同路径然后逐台机器用hadoop version、java -version验证环境变量是否生效。4. 格式化 NameNode 与集群启停顺序和注意事项4.1 格式化只能有一次重蹈覆辙都是 clusterID 惹的祸配置全部完成之后第一次启动前有一个必须做的前置动作格式化 NameNode。命令很简单但背后的坑非常深hdfs namenode -format格式化的本质是在dfs.namenode.name.dir指定的目录下创建一份初始的元数据同时写入一个名为clusterID的唯一标识。所有 DataNode 第一次连接 NameNode 时会拿到这个 clusterID 并记录在本地数据目录的 VERSION 文件里。如果你手贱在集群已经启动之后再次执行格式化NameNode 会生成一个全新的 clusterID而 DataNode 那边的 clusterID 还是旧的两边对不上结果就是 DataNode 反复尝试注册却始终失败。这个问题太常见了。我给的建议是格式化脚本里输出Storage directory ... has been successfully formatted就算成功然后直接把集群启动不要因为好奇再格式化一遍。万一真的格式化了第二次也不是没有办法把 DataNode 上dfs.datanode.data.dir目录里的数据清空再重新启动 DataNode让它以新的 clusterID 重新注册但这样 HDFS 里已有的数据块就全部丢了。所以格式化前务必备份好数据或者干脆把格式化当成一个只能执行一次的操作来对待。4.2 启动顺序先 HDFS 后 YARN停的时候反过来启动集群通常有两个脚本可用start-dfs.sh和start-yarn.sh也可以直接用start-all.sh一条命令全启动。但为了理解集群的层次结构我建议分开执行start-dfs.sh start-yarn.sh为什么必须是这个顺序因为 YARN 的 NodeManager 在启动时会检查 HDFS 是否可用如果 HDFS 还没准备好NodeManager 虽然能起来但是后续的任务提交流程会因为没有文件系统而报错。停止集群时则反过来先stop-yarn.sh停掉计算层再stop-dfs.sh停掉存储层。这样能避免计算任务正在运行的时候底层文件系统突然消失造成数据不一致的风险。启动过程中主节点会通过 SSH 免密依次登录 workers 文件里列的每台机器拉起守护进程。如果你看到某些节点提示Permission denied基本可以断定是 SSH 免密配错了不用怀疑其他原因。启动完成后强烈建议把启动日志认真看一遍不要以为终端没报红色 ERROR 就代表全部正常。4.3 用 jps 和 Web UI 双重确认集群健康验证集群是否起好的第一步是jps命令这是 JDK 自带的小工具专门查看 Java 进程。在主节点上执行jps应该看到NameNodeSecondaryNameNodeResourceManager在从节点上执行jps应该看到DataNodeNodeManager如果进程数量对不上先不要急着重启按下一节里说的排查思路从日志入手。jps看的是进程是否存在但进程存在不等于服务健康。这时要打开 Web UI 做第二重确认NameNode 的 Web 界面地址是http://node01:9870注意是 9870不是 2.x 时代的 50070YARN 的 Web 界面地址是http://node01:8088。在 HDFS Web UI 上能看到 Datanodes 列表确认两个 DataNode 都在线、容量显示正常在 YARN Web UI 上能看到 Active Nodes 的数量两个 NodeManager 都应该列出。这两步都过了集群才算真正“活了”。5. 集群验证传文件、跑任务确认每一层都真的通了5.1 HDFS 基本操作上传、下载、查看集群启动之后第一件事是验证 HDFS 的基本读写。先创建测试目录上传一个本地文件hdfs dfs -mkdir -p /test/input echo hello hadoop hello cluster /home/hadoop/word.txt hdfs dfs -put /home/hadoop/word.txt /test/input/word.txt hdfs dfs -ls /test/input然后验证文件块在 DataNode 上的分布。HDFS 会把大文件切成固定大小的 block默认 128MB对于一个小文件它只对应一个 block但按照我们设置的dfs.replication2这个 block 会被复制两份分别存放在两个 DataNode 上。执行下面这条命令hdfs fsck /test/input/word.txt -files -blocks -locations输出里会列出每个 block 所在的 DataNode 主机名。看到同一个 block 出现在 node02 和 node03 上就说明副本机制真实生效了。这一步往往比看到多少网页界面都有成就感因为这直观地证明了“集群”和“单机”的本质区别。5.2 用官方 WordCount 验证计算链路文件系统确认没问题后再验证计算层。Hadoop 发行包自带示例程序WordCount 是它最经典的“hello world”跑一次就能同时验证 HDFS 读写与 YARN 资源调度的整条链路hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /test/input/word.txt /test/output hdfs dfs -cat /test/output/part-r-00000提交任务后在 YARN 的 Web UI 上能看到一个运行中的 Application点进去可以看到 Map 和 Reduce 的进度以及任务日志的聚合地址。任务跑完后输出目录下会生成part-r-00000文件内容应该类似cluster 1 hadoop 2 hello 2这里有个细节/test/output目录不能是任务运行前已存在的目录否则 Hadoop 会直接拒绝执行。很多新手第一次跑 WordCount 报错org.apache.hadoop.mapred.FileAlreadyExistsException就是这个原因。解决办法很简单跑之前把输出目录删掉或者换一个新名字。6. 搭建过程中最常踩的坑与排查思路6.1 DataNode 起不来先查 clusterID 和目录权限新手集群最容易出现的现象是主节点上进程全在从节点上jps却看不到 DataNode。如果直接重新执行start-dfs.sh也起不来第一步去从节点上找日志cat /usr/local/hadoop/logs/hadoop-hadoop-datanode-node02.log日志里如果出现Incompatible clusterIDs就是第 4.1 节说的格式化导致 clusterID 冲突。解决办法把从节点dfs.datanode.data.dir目录下的文件清空重启 DataNode。日志里如果出现Permission denied大概率是数据目录的属主不是 hadoop 用户执行chown -R hadoop:hadoop /home/hadoop/data后重启。把排查顺序固定下来先看目录权限再看 clusterID最后再看 hosts 映射大部分 DataNode 起不来的场景都能快速定位。6.2 启动时 SSH 报错别急着查防火墙start-dfs.sh执行时卡住或报Permission denied (publickey,gssapi-keyex,password)原因基本可以锁定为 SSH 免密配置失效。常见原因有三类一是密钥对生成时用了 root 用户导致/home/hadoop/.ssh目录属主不对二是~/.ssh/authorized_keys权限过宽SSH 会拒绝加载三是 hosts 里主机名映射不一致主节点尝试连接node02时解析到了错误 IP。我建议用一条命令快速定位在主节点上依次测试ssh -v node02-v参数会输出详细的认证过程看到哪一个环节断开问题就出在哪一层。绝大多数时候把/home/hadoop/.ssh目录权限调整为700、authorized_keys调整为600问题就能解决。6.3 磁盘空间与 /tmp 清理引发的元数据问题集群跑了一段时间后突然发现 NameNode 进入 SafeMode安全模式只允许读不允许写原因可能有两个一是整体磁盘空间不足NameNode 为了保护数据会自动进入只读状态二是有人手动执行了hdfs dfsadmin -safemode enter。如果排除了手动操作就用df -h检查所有节点的磁盘使用率。前面强调过不要把数据目录放在/tmp下正是因为系统或运维脚本清理/tmp是常态元数据一旦被清掉数据目录虽然还在但 NameNode 的 VERSION 文件没了整个文件系统就相当于“失忆”了。遇到这种情况只能做数据恢复或者重建集群没有捷径。6.4 常见报错速查表平时帮人排查问题多了我把最典型的几个报错和对应解法整理成了一个表照着查效率最高报错特征常见原因解决办法Permission denied (publickey)SSH 免密未生效重新生成密钥对并分发确认目录权限Incompatible clusterIDs多次格式化 NameNode清空 DataNode 数据目录重新注册FileAlreadyExistsException输出目录已存在删除输出目录或换新名字mapreduce_shuffle相关错误yarn-site.xml 漏配 aux-services补上mapreduce_shuffle配置Cannot connect to ... 9820core-site.xml 端口写错确认 Hadoop 3.x 的端口是 9820DataNode 反复重连不上hosts 主机名解析失败核对所有节点的 hosts 和主机名NameNode 进入 SafeMode磁盘空间不足清理磁盘或扩展数据目录空间这张表不敢说覆盖全部问题但覆盖了集群搭建入门期 90% 以上的坑。把报错日志和这里对上大多数情况都能在半小时内解决。6.5 一个最容易忽略的“最后一公里”验证节点间时间同步这个坑往往出现在集群跑稳定之后的某一天。你可能会发现某个 DataNode 的 Last Contact 时间越来越长或者任务提交后莫名失败。原因很可能是节点间系统时间偏差过大。Hadoop 的守护进程之间通信有时会依赖时间戳如果 node01 和 node02 的时间差了几分钟就会出现各种“玄学”问题。所以集群搭建完我建议顺手配一下 NTP 时间同步让所有节点的时间保持一致yum install -y chrony systemctl enable chronyd systemctl start chronyd在三台机器上都执行date看一眼时间是否相差很小。这个操作成本极低但能避免后续很多让人抓狂的间歇性故障。你别等到猛然发现集群状态异常时才想起这回事提前做好这套基础保障后面用集群做实验会舒服很多。7. 集群搭好之后再说几句大实话集群跑通、WordCount 出结果的那一刻你算是真正敲开了分布式系统的大门。但我想说这只是一个开始。下一步你可以在这个集群上接着装 Zookeeper然后整合 Hive把 SQL 查询跑起来再往后可以搭 Spark 集群把计算引擎从 MapReduce 换成 Spark感受一下内存计算和磁盘计算的差距。你会发现当时手动搭建时积累的每一个细节——hosts 怎么配、端口怎么改、目录权限怎么设、日志去哪查——在搭这些上层框架的时候都会反复用到就像内功一样。如果你是想完成实验报告或者课程设计这篇文章里给的命令已经足够你交出一份有深度的作业了。但如果你是真的想入行大数据方向我的建议是在搭好的集群上故意搞坏几次比如把 NameNode 格式化第二次、把某个 DataNode 的目录权限改掉、把 YARN 的辅助服务注释掉然后自己排查修复。这个过程比成功搭建一遍更能建立信心因为我就是这么过来的折腾一晚上之后学到的东西比看十篇教程都管用。
返回列表