Hadoop入门:从原理到伪分布式环境搭建全攻略

发布时间:2026/9/18 22:59:04
Hadoop入门:从原理到伪分布式环境搭建全攻略 一提到“大数据”这个词很多人脑子里的第一反应不是别的就是 Hadoop。哪怕这几年 Spark、Flink 这些后起之秀越来越火你去翻各大招聘网站的岗位要求Hadoop 依然是大数据方向的“默认第一课”。原因很简单Hadoop 是整个大数据生态系统的地基HDFS 解决了分布式存储MapReduce 和 YARN 解决了分布式计算与资源调度后面再学 Hive、HBase、Spark你会发现核心思路全都绕不开 Hadoop 这套设计逻辑。这篇教程是我打算写的 Hadoop 入门系列第一篇核心就两件事讲清楚 Hadoop 到底是什么以及怎么把它的开发环境从零搭起来。所有操作我都会按“小白也能照着敲”的标准来写命令、配置文件、启动步骤、踩坑记录全都有。适合刚接触大数据、没怎么碰过 Linux、或者说被各种半截教程坑过的同学也适合看过一些概念但还是不知道手该往哪儿放的人。1. Hadoop 到底是什么先搞懂它解决什么问题1.1 大数据最原始的两个难题人类社会的数据量膨胀到了单个机器根本存不下、算不动的地步这其实才是 Hadoop 出现的真正原因。你可以想象一下你手里有一台 1TB 硬盘的电脑结果公司需要处理 100TB 的日志数据这时候你怎么办存不下是第一个问题就算勉强压缩塞进去了单机几小时算一个任务老板也等不起这是第二个问题。于是就有了一个很朴素的思路一台机器搞不定那就用好多台机器一起搞。但“用好多台机器”这件事听起来简单做起来全是麻烦——数据放在哪台机器上某台机器坏了数据会不会丢一个任务怎么拆给多台机器同时算算完的结果怎么汇总Hadoop 就是把这些麻烦事统一封装起来的框架用一套对外隐藏细节的接口让你像用一台超级电脑一样用一堆普通电脑。上面这段话就是 Hadoop 的核心价值。它不是一个具体的软件而是一个完整的分布式基础架构主要由四个部分协同工作负责存储的 HDFS、负责计算的 MapReduce、负责资源调度的 YARN以及一个公共工具模块 Common。后面你在各种教程里反复看到的 nameNode、dataNode、jobTracker 这些名词全都是这几个组件里的角色。1.2 存储HDFS把大文件切碎了存HDFSHadoop Distributed File System是 Hadoop 的存储层设计目标很简单让成百上千台机器的硬盘组成一个巨大的文件系统。但它不是简单地把文件复制到每台机器上而是把一个文件切成固定大小的数据块默认 128MB 一块然后分散存储到集群的不同节点上。每个数据块默认会有 3 个副本副本数可配置生产环境常用 2 或 3放在不同的机器上。这么做有两大好处第一某台机器坏了数据块在其他机器上还有副本系统自动从副本恢复数据不丢第二一份数据有多份系统可以把读请求分发到不同节点提升读取速度。HDFS 的架构里有两个核心角色NameNode 和 DataNode。你可以把 NameNode 想象成“图书管理员”它不存真正的数据只管一份叫“元数据”的索引记录每个文件被切成了哪些块、这些块分别存在哪些 DataNode 上。DataNode 则是真正的“书架”实实在在存数据块的机器。客户端读写数据时先问 NameNode 要数据块的位置然后直接跟对应的 DataNode 通信整个流程对上层应用是透明的。1.3 计算MapReduce把大任务拆小了算数据存好之后怎么算这就是 MapReduce 的活儿。它的核心思想你肯定听过分而治之。一个超大任务被拆成无数个小的 Map 任务并行处理不同数据块得出中间结果然后再由 Reduce 任务把这些中间结果按某种规则合并得到最终答案。拿统计一个超大文本里每个单词出现次数举例这是 Hadoop 里的“Hello World”。Map 阶段每个数据块被单独统计一次输出形如(hello, 1)、(world, 1)这样的键值对Reduce 阶段把所有相同单词的计数加在一起输出(hello, 3)、(world, 5)。听起来很简单但它在背后解决的是分布式编程里最头疼的问题任务怎么切分、节点之间怎么传数据、某个任务失败怎么重试、结果怎么归并。你只需要实现好 Map 和 Reduce 两个函数剩下的脏活累活框架全包了。可能有人会问都这么多年了写 MapReduce 还得敲 Java是不是落伍了确实现在生产环境很少有人直接裸写 MapReduce大家基本都通过 Hive 用 SQL 去写任务底层由 Hive 帮你翻译成 MapReduce 或 Spark 作业。但理解 MapReduce 的执行模型非常重要它决定了你对“分布式计算到底是怎么跑的”这件事有个直观认知后面学 Hive 调优、学 Spark 的 Shuffle 原理都离不开这层底子。1.4 调度YARN把集群资源统一管起来有了存储、有了计算又冒出一个新问题MapReduce 任务跑的时候要用多少 CPU、多少内存如果好几个任务同时提交资源怎么分配YARNYet Another Resource Negotiator又一个资源协调器就是干这个的。YARN 的基本思路是把集群中每台机器的资源CPU、内存抽象成“资源池”由 ResourceManager 统一管理和分配。你提交一个作业时ResourceManager 会为作业分配需要的资源然后在对应的 NodeManager 上启动一个 Container 来运行任务。这样一来集群资源不再是“谁抢到谁用”而是变成了按需申请、统一调度的模式。MapReduce 只是 YARN 上最常见的计算框架它跑在 YARN 上面Spark 也可以作为 YARN 上的应用来运行彼此是独立又协作的关系。2. 环境配置前的准备版本选择与 Linux 基础2.1 版本选择Hadoop 3.x 还是 2.x新手最容易卡在第一步版本那么多到底下哪个我的建议是直接上 Hadoop 3.x 系列目前比较稳定的是 3.3.x。Hadoop 2.x 虽然教材里讲得很多但它的版本偏老Web UI 默认端口是 50070依赖的 JDK 版本也低学完出去找工作还得重新适应 3.x 的差异没必要在 2.x 上浪费时间。特别注意 JDK 的版本对应关系Hadoop 3.x 最低要求 JDK 8推荐用 JDK 8 或 JDK 11。JDK 版本太高反而可能踩坑比如 Hadoop 某些和 JNI、加密相关的模块在非常新的 JDK 上有兼容性问题所以我给新手的建议是装 OpenJDK 8这是经过大量生产验证的搭配。操作系统方面开发环境推荐 Ubuntu 20.04 或 22.04装个虚拟机或者租一台便宜的云服务器都行。如果你用的是 Windows建议不要直接搞Hadoop 在 Windows 上跑本地模式有很多繁琐的兼容问题新手很容易被劝退。先用虚拟机装 Ubuntu把 Linux 命令练熟了后面学习曲线才平缓。2.2 新建用户与主机名规划很多教程直接让你用 root 用户操作 Hadoop我在实际中非常不建议这么做原因是 Hadoop 的脚本里有一些目录权限判断在 root 下会绕开权限限制导致某些问题不在表面暴露等部署到生产环境才炸出来。而且 Hadoop 集群里各节点之间的通信依赖 SSHroot 用户的 SSH 策略和普通用户也有差异。创建用户的操作新建一个 hadoop 用户统一用它来操作。这一步很简单sudo adduser hadoop # 一路按回车设置密码即可 sudo usermod -aG sudo hadoop # 把 hadoop 用户加入 sudo 组方便后续装软件 su - hadoop # 切换到 hadoop 用户主机名也需要顺手改一下建议改成有意义的名字比如hadoop-node。主机名在 HDFS 配置里经常出现在 URI 中统一命名能少碰很多玄学问题。2.3 JDK 安装与 JAVA_HOME 配置JDK 的安装不要用 apt 默认源版本可能太老建议用 OpenJDK 8 的官方源或者你在 Oracle 官网下 tar 包。下面用 apt 装 OpenJDK 8 的方式演示这是最省事的sudo apt update sudo apt install openjdk-8-jdk java -version确认 java 命令能输出版本信息之后还需要配JAVA_HOME环境变量。Hadoop 的启动脚本不直接读取 PATH 里的 java它找的是JAVA_HOME这一步漏了后面启动必报错。# 找到 JDK 的安装路径 readlink -f $(which java) # 我这边返回的路径是 /usr/lib/jvm/java-8-openjdk-amd64/bin/java然后编辑~/.bashrc在文件末尾加上export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export PATH$PATH:$JAVA_HOME/bin最后执行source ~/.bashrc让配置生效再用echo $JAVA_HOME验证一下。踩过很多次坑之后我建议新手每配完一个环境变量就立刻验证一次不要攒到最后一口气验证不然报错的时候根本分不清是哪一步的问题。2.4 SSH 免密登录配置Hadoop 伪分布式模式虽然只有一台机器但是 Hadoop 的脚本按照“分布式”的逻辑来操作它会通过 SSH 连接到本机去启动 DataNode 和 NodeManager 进程。如果每次连接都要输密码脚本就没法自动执行了所以必须配置 SSH 免密登录。先检查 SSH 服务是否装了、启动了sudo apt install openssh-server sudo service ssh start然后在 hadoop 用户下执行ssh-keygen -t rsa -P -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys ssh localhost最后一条ssh localhost如果直接进入终端而没要密码说明免密配置成功输入exit退出即可。这里有一个很容易被忽略的细节.ssh目录的权限必须是 700authorized_keys文件的权限必须是 600权限太宽松 SSH 会出于安全考虑直接拒绝免密登录。很多教程只让你执行命令却没告诉你后两条 chmod 才是隐藏的关键。3. Hadoop 安装与伪分布式搭建全流程3.1 下载解压与目录规划Hadoop 的官网下载有时候速度不太稳定国内用户可以使用清华大学或者阿里云的镜像站速度快不少。下载时选择 binary 版本的 tar.gz 包不要选 source 包source 是源码需要自己编译才能用速度天差地别。我这里以 3.3.6 版本为例cd /usr/local sudo wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz sudo tar -zxvf hadoop-3.3.6.tar.gz sudo mv hadoop-3.3.6 hadoop sudo chown -R hadoop:hadoop /usr/local/hadoop关于目录规划我建议统一把 Hadoop 放在/usr/local/hadoop并且把所有权授予 hadoop 用户。后面所有配置文件都建议用绝对路径去写不要用~/这种相对路径因为 Hadoop 脚本在一些场景下对相对路径的解析结果可能和你预期不一样用绝对路径能少很多坑。配好之后编辑~/.bashrc添加 Hadoop 的环境变量export HADOOP_HOME/usr/local/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop然后source ~/.bashrc执行hadoop version能看到版本信息就说明环境变量没问题了。3.2 五个关键配置文件逐一解读Hadoop 的配置文件都在$HADOOP_HOME/etc/hadoop目录下。本地模式不需要改任何配置但伪分布式需要修改 5 个文件分别是hadoop-env.sh、core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml。下面我把每个文件干什么、每项参数为什么这么配讲清楚这样以后你上生产环境遇到调优需求也有判断依据。首先改hadoop-env.sh。这个文件是 Hadoop 的环境变量入口Hadoop 的启动脚本会先加载它再启动各个进程。关键是设置 JAVA_HOMEexport JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64新手经常在这里出错这个文件里本来就有个export JAVA_HOME${JAVA_HOME}的模板它会去读系统环境变量里的 JAVA_HOME按理说不用改。但在某些 Linux 发行版或某些用户环境下这个继承逻辑会莫名失效所以我建议直接改成 JDK 的硬编码路径一劳永逸。然后是core-site.xml这是 Hadoop 核心配置伪分布式最常用的就两个属性configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/usr/local/hadoop/tmp/value /property /configurationfs.defaultFS指定了 HDFS 的访问入口客户端要读写数据就是通过这个地址去找 NameNode。hadoop.tmp.dir是 Hadoop 运行时存放临时数据的根目录NameNode 的元数据、DataNode 的数据块文件默认都放在这个目录下。这个参数非常关键如果你不配置它Hadoop 会使用默认的/tmp/hadoop-${user}目录而系统每次重启都可能清空/tmp下的文件一旦被清掉你的 HDFS 元数据就没了表现就是 NameNode 起不来。接着是hdfs-site.xml这个文件主要配置 HDFS 数据相关的参数configuration property namedfs.replication/name value1/value /property property namedfs.namenode.name.dir/name value/usr/local/hadoop/tmp/name/value /property property namedfs.datanode.data.dir/name value/usr/local/hadoop/tmp/data/value /property /configurationdfs.replication是副本数。生产集群默认 3但伪分布式只有一台机器如果设成 3DataNode 会尝试把同一个数据块复制三份放到这台机器上这不仅浪费磁盘还会在写入时反复等待副本确认白白拖慢速度甚至报错。所以一定要设为 1。dfs.namenode.name.dir和dfs.datanode.data.dir是 NameNode 和 DataNode 的数据目录这里我统一放在hadoop.tmp.dir的子目录下方便后续重置集群时统一清理。mapred-site.xml是 MapReduce 的配置这个文件在 Hadoop 3.x 安装包里默认不存在只有一个mapred-site.xml.template模板需要先复制一份再改cp $HADOOP_HOME/etc/hadoop/mapred-site.xml.template $HADOOP_HOME/etc/hadoop/mapred-site.xml文件内容只需指定一个关键参数让 MapReduce 跑在 YARN 上而不是本地configuration property namemapreduce.framework.name/name valueyarn/value /property /configuration最后是yarn-site.xmlYARN 的核心配置伪分布式主要关心 NodeManager 上辅助服务的注册configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property /configurationyarn.nodemanager.aux-services是 YARN 里比较容易费解的参数。简单说NodeManager 作为节点上的资源管家需要知道“上层的计算框架通过这些辅助服务来 shuffle 数据”MapReduce 跑在 YARN 上时就必须配置mapreduce_shuffle。如果机器内存比较小比如只有 2GB建议再加一个参数限制每个容器最多能用的内存量否则启动 YARN 时可能会出现整机内存不够的问题property nameyarn.nodemanager.resource.memory-mb/name value1024/value /property小内存机器另一个常见问题是启动 MapReduce 作业时报“虚拟内存不足”那是容器默认虚拟内存比例过高的原因可以加yarn.nodemanager.vmem-check-enabled并设为false开发环境图省事可以这样调。不过上生产之前一定要改回来这是为了防止单个任务吃爆机器内存。3.3 格式化 NameNode 与启动验证配置文件全部改好之后就可以启动集群了。不过第一步不是启动而是格式化 NameNode。这一步相当于给 HDFS 初始化一个空白文件系统生成 NameNode 所需的元数据结构和集群 ID。hdfs namenode -format看到日志里出现successfully formatted字样就说明格式化成功。有一点必须强调格式化只在第一次启动集群前做一次。之后每次要重置集群要先手动删掉hadoop.tmp.dir目录下的所有数据再重新格式化否则会报 clusterID 不一致的错误。不要养成“启动不了就重新格式化”的习惯在真实生产环境这是灾难性操作。然后启动 HDFS 和 YARNstart-dfs.sh start-yarn.sh执行完可以用jps命令检查进程这是 Java 自带的进程查看工具。一个正常的伪分布式环境jps输出应该包含 5 个进程NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager。少一个都说明对应组件启动有问题要去日志里查。另外两个验证入口是 Web UI。打开浏览器访问http://localhost:9870能看到 HDFS 的管理界面里面有文件系统浏览、集群容量统计、NameNode 日志等访问http://localhost:8088能看到 YARN 的资源管理界面包括正在运行和已结束的任务列表。注意 Hadoop 3.x 的 NameNode Web 端口是 9870不是 2.x 的 50070这个差异我见过一堆人卡住。启动完成后可以快速跑一个最基础的测试——往 HDFS 里放一个文件再读出来echo hello hadoop hdfs /tmp/test.txt hdfs dfs -mkdir /input hdfs dfs -put /tmp/test.txt /input/ hdfs dfs -cat /input/test.txt看到文件内容输出正常说明 HDFS 读写在这台机器上已经通了。3.4 跑通第一个 WordCount 作业存储通了还要验证计算链路。Hadoop 自带了一套 MapReduce 示例代码非常适合做冒烟测试其中最有名的就是 WordCount。执行下面的命令hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /input /output这个命令把 HDFS 上/input目录里所有文件作为输入执行 WordCount结果写到/output目录。执行过程中你有机会在控制台亲眼看到 Map 进度从 0% 走到 100%Reduce 阶段接着从 0% 走到 100%这时你对“分布式任务怎么分阶段跑”会有一个非常直观的认识。跑完以后查看结果hdfs dfs -cat /output/part-r-00000如果看到了类似hadoop 1、hello 1、hdfs 1这样的单词计数输出就说明从 HDFS 存储到 YARN 调度再到 MapReduce 计算整条链路全部打通了。到这一步你的 Hadoop 伪分布式开发环境就算彻底搭好了。之后写 MapReduce 代码、跑 Hive 测试都建立在今天这个环境之上。4. 实操中的常见问题与排查技巧4.1 jps 看不到完整进程怎么办环境搭好后最容易遇到的问题就是进程起不全。jps 里少了 NameNode 或 DataNode这个概率非常高。出现这种情况我的建议是不要瞎猜直接看日志。Hadoop 每个进程的日志目录在$HADOOP_HOME/logs下文件命名很直白hadoop-hadoop-namenode-主机名.log、hadoop-hadoop-datanode-主机名.log你用 tail 命令查看末尾几十行tail -50 $HADOOP_HOME/logs/hadoop-hadoop-namenode-*.log常见报错之一是在启动时 HDFS 的 DataNode 一直报Block pool ID needed之类的错误十有八九是因为你格式化过 NameNode 多次导致 DataNode 记录的集群 ID 和 NameNode 当前的不一致。这种情况只要清掉 tmp 目录重新格式化就能解决但前提是你确定不需要保留 HDFS 里已有的数据。另一个很常见的坑是端口被占用。如果之前有一次启动失败但残留了某些 Java 进程再次启动时会报Address already in use。排查方法netstat -tunlp | grep 9870找到占用端口的进程 PID用kill -9 PID清掉再重新启动对应服务。4.2 格式化后 NameNode 仍然起不来如果你执行了hdfs namenode -format也看到了 success但 start-dfs.sh 后 jps 里就是没有 NameNode日志里报的是类似Java.io.IOException: NameNode is not formatted或者找不到current/VERSION文件这通常说明 hadoop.tmp.dir 的路径在core-site.xml里没生效。怎么验证看 NameNode 日志里打印的目录路径是不是你在 xml 里写的那一个。很常见的误导是你在 core-site.xml 里写了/usr/local/hadoop/tmp但 Hadoop 实际去读的目录是/tmp/hadoop-hadoop说明配置文件的 XML 格式有问题或者文件没被正确加载。这时检查 XML 标签是否闭合尤其注意configuration和/configuration是否完整以及有没有多余的特殊字符。XML 配置文件在解析时代码里少一个尖括号、多一个空格都可能引发诡异问题。还有一个非常容易忽略的点hadoop.tmp.dir指向的目录必须已经赋予了 hadoop 用户写权限。我之前用 root 解压安装 Hadoop后来切到普通用户启动结果 NameNode 一直报权限不足当时排查了好久才发现是/usr/local/hadoop的所有权还挂在 root 名下。解决方式是回到第 3 章开头那步确保/usr/local/hadoop已经chown -R给当前用户。4.3 SSH 免密配好了却没生效伪分布式启动时SSH 免密不生效也是一个极其常见的问题。表现是执行start-dfs.sh时每次启动 DataNode 都提示输入密码或者报Permission denied (publickey)。这时候按顺序排查三点。第一确认当前执行ssh localhost的是哪个用户。配置免密时是在 hadoop 用户下执行的启动脚本也必须用同一个用户如果在 root 下执行启动免密当然不生效。第二检查.ssh目录权限chmod 700 ~/.ssh和chmod 600 ~/.ssh/authorized_keys这两条命令一定要执行。第三确认authorized_keys文件里是否真的包含了 id_rsa.pub 的内容可以用cat ~/.ssh/authorized_keys查看如果文件是空的说明追加操作没成功重新执行一次cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys。4.4 内存不足与 Web UI 打不开很多人的虚拟机只分配了 1GB 或 2GB 内存跑伪分布式时机身内存不足表现通常是 YARN 启动后很快 NodeManager 或者 ResourceManager 进程被系统杀掉或者提交 WordCount 任务时一直卡在 ACCEPTED 状态不调度。遇到这个问题建议给虚拟机分配至少 2GB 内存如果内存本来就有限就调小 YARN 容器可用内存参考第 3.2 节里那个yarn.nodemanager.resource.memory-mb参数。Web UI 打不开则需要分情况。如果http://localhost:9870打不开但jps里 NameNode 进程是存在的优先检查防火墙。Ubuntu 默认的 ufw 防火墙如果开启了会把外网访问挡在门外最简单的方式是在本机测试时直接关闭防火墙或者放行指定端口sudo ufw disable另外如果你是用远程服务器、云主机部署注意安全组策略也要放行 9870 和 8088 端口否则你的浏览器从自己电脑上访问不到 Web UI。这个问题和 Hadoop 本身没关系但实际中遇到的人非常多值得列出来提醒一句。4.5 开发调试的几条实用建议环境搭好之后日常学习和调试过程中我建议养成几个习惯。第一每次改完配置文件先执行hdfs dfsadmin -report检查 HDFS 集群状态再执行yarn node -list检查 YARN 节点状态比直接跑作业更早发现环境问题。第二跑完了的测试作业输出目录要及时清理因为 MapReduce 作业要求输出目录不存在才能运行第二次跑同样的输出路径会直接报错你得先进 Web UI 或执行hdfs dfs -rm -r /output删除。第三启动和停止集群尽量用start-dfs.sh/stop-dfs.sh、start-yarn.sh/stop-yarn.sh成对操作不要直接杀进程否则残留的临时状态会在下一次启动时制造出莫名其妙的故障。以我个人的经验前端几个系列面试中关于 Hadoop 的题目往往不是问它怎么用而是问“你有没有在伪分布式环境上实际跑通过任务”。这个环境配置看起来繁琐但它是你把概念落到实处的第一道门槛。我第一次搭的时候也被 XML 配置文件折磨过两三天后来发现只要理解了每个参数的含义照着思路理一遍再动手就非常快了。环境搭好之后别急着往下冲先多跑几遍 WordCount把 jps 里那几个进程看熟了再去折腾伪分布式和真集群的差异你会觉得后面每一步都轻松很多。