1. 为什么我要重新认真梳理Hadoop入门这件事大数据这个词现在几乎成了每个技术团队的标配,不管你是做后端、做数据分析还是做运维,只要公司数据量一上来,Hadoop这三个字就绕不开。但说实话,我见过太多人卡在入门这一步——不是被MapReduce的编程模型绕晕,就是被一堆配置文件搞得头大,再不然就是环境搭起来了却不知道下一步该干什么。我自己当年第一次接触Hadoop的时候,光是让一个WordCount跑起来就折腾了整整两天,踩的坑包括但不限于:Java环境变量没配对、core-site.xml里fs.defaultFS写错、datanode死活起不来、防火墙没关导致节点之间通信失败。这些坑现在回头看都是小儿科,但当时每一个都足以让人想砸键盘。这篇内容就是把我这些年带新人、做内部培训、以及自己反复折腾Hadoop的经验整理出来,目标很明确:让你从零开始,真正理解Hadoop的核心设计思想,能独立完成单机和伪分布式环境的搭建,能跑通第一个MapReduce程序,并且知道遇到常见问题该怎么排查。不管你是刚入行的开发,还是从其他方向转过来的运维,或者是学生党想补一下大数据基础,这篇都能给你一条清晰的路径。我不会只给你一堆命令让你复制粘贴,而是会把每个步骤背后的“为什么”讲清楚——为什么Hadoop要这么设计、为什么这个参数要这么配、为什么这个操作顺序不能反。只有理解了这些,你后面遇到变体场景才不会慌。2. Hadoop到底解决了什么问题,它的核心设计思路是什么2.1 从“一台机器扛不住”说起假设你手里有一个100GB的日志文件,想统计里面每个URL被访问了多少次。用传统做法,你写个Python脚本逐行读、用字典计数,在一台普通服务器上跑,可能几个小时也能出结果。但如果文件变成10TB呢?单台机器的磁盘IO、内存、CPU都会成为瓶颈,更别说万一这台机器中途挂了,整个任务就得重来。Hadoop要解决的就是这类问题:数据量大到单机存不下、算不动,而且还要考虑容错。它的核心思路可以用一句话概括:把数据切开放到多台机器上,把计算逻辑也搬到数据所在的机器上执行,最后把各台机器的局部结果汇总起来。这就是所谓的“移动计算比移动数据更划算”。你想想,10TB数据如果通过网络传输到一台超级计算机上,网络带宽就是第一个瓶颈;但如果每台机器只处理自己本地的那一小块数据,网络传输的就只是中间结果和最终结果,量级完全不一样。2.2 HDFS:把大文件切成块,分散存储HDFS(Hadoop Distributed File System)是Hadoop的存储底座。它的设计哲学很直接:文件被切成固定大小的块(Block),默认在Hadoop 2.x和3.x里是128MB(Hadoop 1.x是64MB),每个块会被复制多份(默认3副本),分散存放在不同机器上。这样做的好处有三个:第一,单台机器存不下的大文件被拆成了小块,可以放到多台机器上;第二,多副本保证了即使某台机器硬盘坏了,数据也不会丢;第三,读取的时候可以并行从多个节点读不同的块,吞吐量上去了。这里有个关键角色叫NameNode,它不存实际数据,只记录“哪个文件由哪些块组成、每个块在哪些机器上”这些元数据。实际数据存在DataNode上。你访问HDFS的时候,先找NameNode问“我要读的这个文件,块都在哪儿”,然后直接去对应的DataNode读数据。这种架构的瓶颈也很明显:NameNode是单点,一旦挂了整个集群就废了(Hadoop 2.x之后通过HA方案解决了这个问题,但这是后话)。入门阶段你先理解这个主从结构就行。2.3 MapReduce:分而治之的计算模型MapReduce把计算过程抽象成两个阶段:Map和Reduce。Map阶段负责“拆分”,把大任务拆成一个个小任务并行处理;Reduce阶段负责“汇总”,把小任务的结果合并成最终结果。中间还有一个Shuffle阶段,负责把Map的输出按照key重新分发到不同的Reduce任务上。拿WordCount举例:输入是几行文本,Map阶段把每一行拆成单词,输出<单词, 1>这样的键值对;Shuffle阶段把所有相同的单词分到同一个Reduce任务;Reduce阶段把同一个单词的所有1加起来,得到<单词, 总数>。这个模型的好处是,你只需要关注Map和Reduce的逻辑,底层的并行调度、容错、数据分发都由框架帮你搞定。坏处是,很多现实问题并不能简单地用两个阶段表达,所以后来才有了Spark、Flink这些更灵活的框架。但作为入门,MapReduce是理解分布式计算思想最好的切入点。2.4 YARN:把资源管理和计算框架解耦在Hadoop 1.x时代,MapReduce既是计算框架又是资源调度器,导致集群只能跑MapReduce任务。Hadoop 2.x引入了YARN(Yet Another Resource Negotiator),把资源管理抽出来单独做一层。YARN负责管理集群的CPU、内存等资源,然后各个计算框架(MapReduce、Spark、Flink等)作为YARN上的应用来申请资源运行。这样同一个集群可以跑多种任务,资源利用率也更高了。YARN的核心组件包括ResourceManager(全局资源调度)、NodeManager(单节点资源管理)和ApplicationMaster(每个应用的管理者)。入门阶段你不需要深究YARN的内部调度算法,但要知道你的MapReduce任务在YARN上运行时,会先启动一个ApplicationMaster,由它去申请Container来跑Map和Reduce任务。理解这一点,后面看日志和排查问题会清晰很多。3. 动手之前:环境准备与版本选择的那些坑3.1 选哪个版本,别一上来就追新Hadoop的版本号看起来有点乱,但入门阶段你只需要关注两条线:Hadoop 2.x和Hadoop 3.x。2.x系列最成熟稳定,网上资料最多,很多公司生产环境还在用2.7、2.8、2.9这些版本。3.x系列引入了很多新特性,比如支持纠删码、多NameNode联邦、更好的性能优化,但资料相对少一些,踩坑时能搜到的答案也少。我的建议是:入门用Hadoop 3.x的稳定版,比如3.3.x或3.4.x。原因很简单,3.x对Java版本的支持更好(支持Java 8和Java 11),而且很多新项目已经直接上3.x了,你学了2.x的配置方式,到3.x可能还要重新适应。但如果你所在的公司明确用2.x,那你就跟着公司的版本来,别自己另搞一套。Java版本方面,Hadoop 3.3+推荐用Java 8或Java 11。Java 8最稳,几乎所有Hadoop版本都兼容;Java 11在3.3之后支持得也不错,但有些老组件可能还有问题。入门阶段直接用Java 8,省心。3.2 单机模式、伪分布式、完全分布式,先搞哪个Hadoop的部署模式有三种:单机模式(Local Mode):所有东西跑在一个JVM里,用的是本地文件系统,不是HDFS。适合你只想跑一下MapReduce程序逻辑,不关心分布式环境。伪分布式模式(Pseudo-Distributed Mode):所有Hadoop守护进程(NameNode、DataNode、ResourceManager、NodeManager)都跑在一台机器上,但用的是HDFS和YARN。适合学习Hadoop的完整功能,也是入门最推荐的模式。完全分布式模式(Fully Distributed Mode):多台机器组成真正的集群。适合生产环境或者你想深入学习集群运维。入门阶段,直接上伪分布式。单机模式太简单,学不到HDFS和YARN的东西;完全分布式又需要多台机器或者多个虚拟机,对新手来说复杂度太高。伪分布式能让你在一台机器上体验完整的Hadoop功能,包括HDFS的文件操作、YARN的任务调度、MapReduce的分布式执行流程。等你把伪分布式玩熟了,再扩展到完全分布式就是加机器和改配置的事。3.3 操作系统和基础环境Linux是首选,Ubuntu或CentOS都行。如果你用的是Windows,建议装个虚拟机跑Ubuntu,别在Windows上直接搞Hadoop,各种路径和权限问题会让你怀疑人生。我见过有人在Windows上折腾Cygwin跑Hadoop,最后放弃了,纯属浪费时间。基础环境需要准备这些东西:JDK:安装Java 8,配置好JAVA_HOME环境变量。验证方式:java -version和echo $JAVA_HOME都能正常输出。SSH:伪分布式模式下,Hadoop的脚本需要通过SSH登录到本机来启动守护进程。你需要配置本机免密登录:ssh-keygen -t rsa生成密钥,然后ssh-copy-id localhost把公钥加到authorized_keys里。验证方式:ssh localhost不需要输密码就能登录。主机名和hosts:给机器设个主机名,比如hadoop-node1,然后在/etc/hosts里加上127.0.0.1 hadoop-node1。这一步很多人忽略,但后面配置HDFS的fs.defaultFS和YARN的resourcemanager地址时都会用到主机名,提前配好省得后面改来改去。防火墙:入门阶段直接把防火墙关了,或者放行Hadoop用到的端口(NameNode的9870、DataNode的9864、ResourceManager的8088等)。防火墙没关是新手最常见的坑之一,症状是各个进程都起来了,但Web UI打不开或者节点之间通信失败。注意:如果你是在云服务器上搭环境,除了系统防火墙,还要检查安全组规则有没有放行对应端口。我遇到过有人在云服务器上搭好了,本地浏览器死活打不开9870端口,折腾半天才发现是安全组没配。4. 伪分布式环境搭建:一步一步来,别跳步4.1 下载和解压从Apache官网下载Hadoop的二进制包,注意要下binary版本,不是source版本。下载地址自己搜一下“Apache Hadoop releases”就能找到。下载完之后解压到你喜欢的目录,比如/opt/hadoop或者~/hadoop。我习惯放在/opt下面,因为路径短,后面配环境变量方便。tar -xzvf hadoop-3.3.6.tar.gz -C /opt/ mv /opt/hadoop-3.3.6 /opt/hadoop解压完之后,把Hadoop的bin和sbin目录加到PATH里,方便后面直接敲命令。在~/.bashrc或者~/.bash_profile里加上:export HADOOP_HOME=/opt/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin然后source ~/.bashrc让配置生效。验证方式:hadoop version能输出版本信息就说明PATH配对了。4.2 配置Hadoop的五个核心文件Hadoop的配置文件都在$HADOOP_HOME/etc/hadoop/目录下。伪分布式模式需要改五个文件,我一个个说。第一个:hadoop-env.sh这个文件里要设置JAVA_HOME。找到export JAVA_HOME=那一行,改成你实际的Java安装路径。比如:export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64很多人这里写错路径,导致后面启动时报“JAVA_HOME is not set”或者“Error: JAVA_HOME is incorrectly set”。验证方式:echo $JAVA_HOME输出的路径和这个文件里写的一致,并且该路径下确实有bin/java这个可执行文件。第二个:core-site.xml这个文件配的是Hadoop的全局参数,最重要的是fs.defaultFS,指定HDFS的地址。伪分布式下写成:<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop-node1:9870</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop/tmp</value> </property> </configuration>注意hdfs://hadoop-node1:9870里的主机名要和你之前配的hosts一致。hadoop.tmp.dir是Hadoop的临时目录,默认在/tmp下面,但/tmp重启后可能会被清空,导致NameNode的元数据丢失,所以最好改到一个持久化的目录。第三个:hdfs-site.xml这个文件配HDFS相关的参数。伪分布式下主要配副本数,因为只有一台机器,副本数设成1就行,设成3会一直报“副本不足”的警告。<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/opt/hadoop/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/opt/hadoop/data/datanode</value> </property> </configuration>dfs.namenode.name.dir和dfs.datanode.data.dir分别指定NameNode和DataNode的数据存储目录。不配的话会用默认值,但默认值也在/tmp下面,同样有丢失风险。第四个:mapred-site.xml这个文件配MapReduce相关的参数。伪分布式下要告诉Hadoop用YARN来跑MapReduce:<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.application.classpath</name> <value>$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/mapreduce/lib/*</value> </property> </configuration>mapreduce.application.classpath这个参数在Hadoop 3.x里比较重要,不配的话跑MapReduce任务时可能报ClassNotFoundException。第五个:yarn-site.xml这个文件配YARN相关的参数:<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop-node1</value> </property> </configuration>yarn.nodemanager.aux-services必须设成mapreduce_shuffle,否则MapReduce任务跑不起来。yarn.resourcemanager.hostname指定ResourceManager所在的主机名。4.3 格式化NameNode和启动集群配置改完之后,第一次启动前需要格式化NameNode:hdfs namenode -format这个命令会创建NameNode的元数据目录。注意:格式化只能做一次,如果你后面改了配置想重新格式化,必须先把之前生成的namenode和datanode数据目录删掉,否则会导致clusterID不一致,DataNode起不来。我见过有人反复格式化,最后DataNode死活连不上NameNode,就是因为没删旧数据。格式化成功后,启动HDFS:start-dfs.sh然后启动YARN:start-yarn.sh启动完成后,用jps命令检查进程。正常应该看到NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager这五个进程。如果少了哪个,去对应的日志目录(默认在$HADOOP_HOME/logs/)看错误信息。4.4 验证环境是否正常打开浏览器,访问http://hadoop-node1:9870,这是NameNode的Web UI。能看到Overview页面说明HDFS起来了。再访问http://hadoop-node1:8088,这是ResourceManager的Web UI,能看到集群资源信息说明YARN也正常。然后在HDFS上建个目录测试一下:hdfs dfs -mkdir -p /user/yourname hdfs dfs -ls /能正常列出目录就说明HDFS读写没问题。5. 跑通第一个MapReduce程序:WordCount完整实操5.1 准备输入数据先在本地建一个文本文件,随便写几行英文,比如:hello world hello hadoop hadoop is great hello mapreduce然后把这个文件上传到HDFS:hdfs dfs -mkdir -p /user/yourname/input hdfs dfs -put wordcount.txt /user/yourname/input/用hdfs dfs -ls /user/yourname/input/确认文件上传成功。5.2 运行自带的WordCount示例Hadoop的安装包里自带了一个WordCount的示例jar包,路径在$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar。直接跑:hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /user/yourname/input /user/yourname/output这个命令的意思是:用hadoop-mapreduce-examples这个jar包里的wordcount类,处理HDFS上/user/yourname/input目录下的所有文件,结果输出到/user/yourname/output目录。注意输出目录必须不存在,否则会报“Output directory already exists”。这是Hadoop的一个保护机制,防止你误覆盖之前的结果。5.3 查看运行结果任务跑完后,查看输出:hdfs dfs -ls /user/yourname/output hdfs dfs -cat /user/yourname/output/part-r-00000part-r-00000是Reduce任务的输出文件,r表示这是Reduce阶段的输出。你会看到每个单词和它的出现次数,按字母顺序排列。5.4 理解任务执行过程在任务运行期间,你可以通过ResourceManager的Web UI(8088端口)看到这个应用的执行状态。点进去能看到ApplicationMaster的页面,里面有Map任务和Reduce任务的进度、每个任务的运行节点、耗时等信息。这是理解MapReduce执行流程最直观的方式。整个流程大致是这样的:客户端提交任务到ResourceManager,ResourceManager找一个NodeManager启动ApplicationMaster,ApplicationMaster向ResourceManager申请Container来跑Map任务和Reduce任务。Map任务读取HDFS上的输入分片,处理后输出中间结果到本地磁盘;Shuffle阶段把中间结果按key分发到Reduce任务;Reduce任务汇总后把最终结果写回HDFS。6. 常见问题与排查技巧实录6.1 启动时报“Connection refused”这是最常见的错误之一。症状是执行start-dfs.sh或start-yarn.sh时,日志里出现“Connection refused”或者“Retrying connect to server”。原因通常是SSH免密登录没配好,或者主机名解析有问题。排查步骤:先确认ssh localhost能不能免密登录,如果不能,重新配SSH密钥;如果能,检查/etc/hosts里主机名和IP的映射是否正确,以及Hadoop配置文件里用的主机名是否和hosts里一致。6.2 DataNode启动后马上消失jps看到DataNode进程一闪而过,或者启动后几秒钟就没了。去$HADOOP_HOME/logs/目录下看DataNode的日志,常见原因有两个:一是多次格式化NameNode导致clusterID不一致,解决方法是删掉namenode和datanode的数据目录,重新格式化一次;二是数据目录权限不对,Hadoop进程没有写权限,解决方法是把数据目录的owner改成运行Hadoop的用户。6.3 Web UI打不开进程都起来了,但浏览器访问9870或8088端口打不开。排查顺序:先在服务器上用curl http://localhost:9870看能不能返回内容,如果能,说明是网络或防火墙问题;如果不能,说明服务本身没起来。防火墙问题在Linux上用systemctl status firewalld或ufw status检查,云服务器还要检查安全组。另外注意,Hadoop 3.x的NameNode Web UI端口是9870,不是2.x时代的50070,别搞混了。6.4 MapReduce任务卡在ACCEPTED状态任务提交后一直显示ACCEPTED,不进入RUNNING状态。这通常是YARN资源不够,比如NodeManager的内存配置太小,或者集群资源被其他任务占满了。去ResourceManager的Web UI看集群资源情况,如果Available Memory是0,说明资源不够。可以调大yarn.nodemanager.resource.memory-mb的值,或者等其他任务跑完。6.5 任务报“ClassNotFoundException”跑MapReduce任务时出现ClassNotFoundException,通常是mapreduce.application.classpath没配好,或者jar包里的类路径不对。检查mapred-site.xml里的mapreduce.application.classpath配置,确保包含了$HADOOP_HOME/share/hadoop/mapreduce/*和$HADOOP_HOME/share/hadoop/mapreduce/lib/*。问题现象可能原因排查方法解决方案Connection refusedSSH免密未配或主机名解析失败测试ssh localhost,检查/etc/hosts重新配SSH密钥,修正hosts映射DataNode启动后消失clusterID不一致或目录权限问题查看DataNode日志删数据目录重新格式化,修正权限Web UI打不开防火墙或安全组未放行curl localhost测试,检查防火墙关闭防火墙或放行端口任务卡在ACCEPTEDYARN资源不足查看ResourceManager UI资源状态调大NodeManager内存配置ClassNotFoundExceptionclasspath配置缺失检查mapred-site.xml补全mapreduce.application.classpath提示:每次改完配置文件,都需要重启对应的Hadoop服务才能生效。改HDFS配置重启HDFS,改YARN配置重启YARN。重启命令分别是stop-dfs.sh/start-dfs.sh和stop-yarn.sh/start-yarn.sh。7. 入门之后往哪走:几个值得深入的方向把伪分布式跑通、WordCount跑成功之后,你算是正式入了Hadoop的门。但入门只是起点,后面还有几个方向值得深入。第一个是完全分布式集群搭建,把NameNode、ResourceManager、DataNode、NodeManager分散到多台机器上,理解HA(High Availability)方案怎么配,这是生产环境的基本要求。第二个是自己写MapReduce程序,不要只跑示例,用Java写一个自己的Mapper和Reducer,理解InputFormat、OutputFormat、Partitioner、Combiner这些组件的作用。第三个是HDFS的底层原理,包括NameNode的元数据管理、DataNode的块存储、副本放置策略、读写流程等,这些理解了,后面调优和排查问题会轻松很多。第四个是YARN的资源调度,了解FIFO、Capacity、Fair三种调度器的区别和适用场景。我个人建议的顺序是:先把伪分布式玩熟,然后自己写几个MapReduce程序(比如统计日志里的IP访问次数、计算每个用户的平均消费金额),再搭一个三节点的完全分布式集群,最后再去深入原理。不要一上来就啃源码或者看调度算法,那样容易劝退。动手跑起来、看到结果、遇到问题、解决问题,这个循环才是最快的学习路径。另外说一个我自己的体会:Hadoop的很多设计思想(分而治之、移动计算、副本容错)在后面的Spark、Flink里都能看到影子。所以入门阶段不要只盯着Hadoop的API和配置,多想想它为什么这么设计,这些思想才是真正能迁移到其他技术栈的东西。我见过不少人Hadoop命令敲得很溜,但问他“为什么HDFS的块大小默认是128MB而不是1GB”,就答不上来了。这种只记操作不理解原理的学习方式,遇到新问题就容易卡住。最后再分享一个小技巧:搭建环境的时候,每改一个配置文件就重启一次服务并验证,不要一次性改完所有文件再启动。这样出问题的时候你能快速定位是哪个配置改错了。我当年就是一次性改了五个文件然后启动失败,挨个排查花了半天,后来养成“改一个验一个”的习惯,效率反而高了很多。
1. 为什么我要重新认真梳理Hadoop入门这件事大数据这个词现在几乎成了每个技术团队的标配,不管你是做后端、做数据分析还是做运维,只要公司数据量一上来,Hadoop这三个字就绕不开。但说实话,我见过太多人卡在入门这一步——不是被MapReduce的编程模型绕晕,就是被一堆配置文件搞得头大,再不然就是环境搭起来了却不知道下一步该干什么。我自己当年第一次接触Hadoop的时候,光是让一个WordCount跑起来就折腾了整整两天,踩的坑包括但不限于:Java环境变量没配对、core-site.xml里fs.defaultFS写错、datanode死活起不来、防火墙没关导致节点之间通信失败。这些坑现在回头看都是小儿科,但当时每一个都足以让人想砸键盘。这篇内容就是把我这些年带新人、做内部培训、以及自己反复折腾Hadoop的经验整理出来,目标很明确:让你从零开始,真正理解Hadoop的核心设计思想,能独立完成单机和伪分布式环境的搭建,能跑通第一个MapReduce程序,并且知道遇到常见问题该怎么排查。不管你是刚入行的开发,还是从其他方向转过来的运维,或者是学生党想补一下大数据基础,这篇都能给你一条清晰的路径。我不会只给你一堆命令让你复制粘贴,而是会把每个步骤背后的“为什么”讲清楚——为什么Hadoop要这么设计、为什么这个参数要这么配、为什么这个操作顺序不能反。只有理解了这些,你后面遇到变体场景才不会慌。2. Hadoop到底解决了什么问题,它的核心设计思路是什么2.1 从“一台机器扛不住”说起假设你手里有一个100GB的日志文件,想统计里面每个URL被访问了多少次。用传统做法,你写个Python脚本逐行读、用字典计数,在一台普通服务器上跑,可能几个小时也能出结果。但如果文件变成10TB呢?单台机器的磁盘IO、内存、CPU都会成为瓶颈,更别说万一这台机器中途挂了,整个任务就得重来。Hadoop要解决的就是这类问题:数据量大到单机存不下、算不动,而且还要考虑容错。它的核心思路可以用一句话概括:把数据切开放到多台机器上,把计算逻辑也搬到数据所在的机器上执行,最后把各台机器的局部结果汇总起来。这就是所谓的“移动计算比移动数据更划算”。你想想,10TB数据如果通过网络传输到一台超级计算机上,网络带宽就是第一个瓶颈;但如果每台机器只处理自己本地的那一小块数据,网络传输的就只是中间结果和最终结果,量级完全不一样。2.2 HDFS:把大文件切成块,分散存储HDFS(Hadoop Distributed File System)是Hadoop的存储底座。它的设计哲学很直接:文件被切成固定大小的块(Block),默认在Hadoop 2.x和3.x里是128MB(Hadoop 1.x是64MB),每个块会被复制多份(默认3副本),分散存放在不同机器上。这样做的好处有三个:第一,单台机器存不下的大文件被拆成了小块,可以放到多台机器上;第二,多副本保证了即使某台机器硬盘坏了,数据也不会丢;第三,读取的时候可以并行从多个节点读不同的块,吞吐量上去了。这里有个关键角色叫NameNode,它不存实际数据,只记录“哪个文件由哪些块组成、每个块在哪些机器上”这些元数据。实际数据存在DataNode上。你访问HDFS的时候,先找NameNode问“我要读的这个文件,块都在哪儿”,然后直接去对应的DataNode读数据。这种架构的瓶颈也很明显:NameNode是单点,一旦挂了整个集群就废了(Hadoop 2.x之后通过HA方案解决了这个问题,但这是后话)。入门阶段你先理解这个主从结构就行。2.3 MapReduce:分而治之的计算模型MapReduce把计算过程抽象成两个阶段:Map和Reduce。Map阶段负责“拆分”,把大任务拆成一个个小任务并行处理;Reduce阶段负责“汇总”,把小任务的结果合并成最终结果。中间还有一个Shuffle阶段,负责把Map的输出按照key重新分发到不同的Reduce任务上。拿WordCount举例:输入是几行文本,Map阶段把每一行拆成单词,输出<单词, 1>这样的键值对;Shuffle阶段把所有相同的单词分到同一个Reduce任务;Reduce阶段把同一个单词的所有1加起来,得到<单词, 总数>。这个模型的好处是,你只需要关注Map和Reduce的逻辑,底层的并行调度、容错、数据分发都由框架帮你搞定。坏处是,很多现实问题并不能简单地用两个阶段表达,所以后来才有了Spark、Flink这些更灵活的框架。但作为入门,MapReduce是理解分布式计算思想最好的切入点。2.4 YARN:把资源管理和计算框架解耦在Hadoop 1.x时代,MapReduce既是计算框架又是资源调度器,导致集群只能跑MapReduce任务。Hadoop 2.x引入了YARN(Yet Another Resource Negotiator),把资源管理抽出来单独做一层。YARN负责管理集群的CPU、内存等资源,然后各个计算框架(MapReduce、Spark、Flink等)作为YARN上的应用来申请资源运行。这样同一个集群可以跑多种任务,资源利用率也更高了。YARN的核心组件包括ResourceManager(全局资源调度)、NodeManager(单节点资源管理)和ApplicationMaster(每个应用的管理者)。入门阶段你不需要深究YARN的内部调度算法,但要知道你的MapReduce任务在YARN上运行时,会先启动一个ApplicationMaster,由它去申请Container来跑Map和Reduce任务。理解这一点,后面看日志和排查问题会清晰很多。3. 动手之前:环境准备与版本选择的那些坑3.1 选哪个版本,别一上来就追新Hadoop的版本号看起来有点乱,但入门阶段你只需要关注两条线:Hadoop 2.x和Hadoop 3.x。2.x系列最成熟稳定,网上资料最多,很多公司生产环境还在用2.7、2.8、2.9这些版本。3.x系列引入了很多新特性,比如支持纠删码、多NameNode联邦、更好的性能优化,但资料相对少一些,踩坑时能搜到的答案也少。我的建议是:入门用Hadoop 3.x的稳定版,比如3.3.x或3.4.x。原因很简单,3.x对Java版本的支持更好(支持Java 8和Java 11),而且很多新项目已经直接上3.x了,你学了2.x的配置方式,到3.x可能还要重新适应。但如果你所在的公司明确用2.x,那你就跟着公司的版本来,别自己另搞一套。Java版本方面,Hadoop 3.3+推荐用Java 8或Java 11。Java 8最稳,几乎所有Hadoop版本都兼容;Java 11在3.3之后支持得也不错,但有些老组件可能还有问题。入门阶段直接用Java 8,省心。3.2 单机模式、伪分布式、完全分布式,先搞哪个Hadoop的部署模式有三种:单机模式(Local Mode):所有东西跑在一个JVM里,用的是本地文件系统,不是HDFS。适合你只想跑一下MapReduce程序逻辑,不关心分布式环境。伪分布式模式(Pseudo-Distributed Mode):所有Hadoop守护进程(NameNode、DataNode、ResourceManager、NodeManager)都跑在一台机器上,但用的是HDFS和YARN。适合学习Hadoop的完整功能,也是入门最推荐的模式。完全分布式模式(Fully Distributed Mode):多台机器组成真正的集群。适合生产环境或者你想深入学习集群运维。入门阶段,直接上伪分布式。单机模式太简单,学不到HDFS和YARN的东西;完全分布式又需要多台机器或者多个虚拟机,对新手来说复杂度太高。伪分布式能让你在一台机器上体验完整的Hadoop功能,包括HDFS的文件操作、YARN的任务调度、MapReduce的分布式执行流程。等你把伪分布式玩熟了,再扩展到完全分布式就是加机器和改配置的事。3.3 操作系统和基础环境Linux是首选,Ubuntu或CentOS都行。如果你用的是Windows,建议装个虚拟机跑Ubuntu,别在Windows上直接搞Hadoop,各种路径和权限问题会让你怀疑人生。我见过有人在Windows上折腾Cygwin跑Hadoop,最后放弃了,纯属浪费时间。基础环境需要准备这些东西:JDK:安装Java 8,配置好JAVA_HOME环境变量。验证方式:java -version和echo $JAVA_HOME都能正常输出。SSH:伪分布式模式下,Hadoop的脚本需要通过SSH登录到本机来启动守护进程。你需要配置本机免密登录:ssh-keygen -t rsa生成密钥,然后ssh-copy-id localhost把公钥加到authorized_keys里。验证方式:ssh localhost不需要输密码就能登录。主机名和hosts:给机器设个主机名,比如hadoop-node1,然后在/etc/hosts里加上127.0.0.1 hadoop-node1。这一步很多人忽略,但后面配置HDFS的fs.defaultFS和YARN的resourcemanager地址时都会用到主机名,提前配好省得后面改来改去。防火墙:入门阶段直接把防火墙关了,或者放行Hadoop用到的端口(NameNode的9870、DataNode的9864、ResourceManager的8088等)。防火墙没关是新手最常见的坑之一,症状是各个进程都起来了,但Web UI打不开或者节点之间通信失败。注意:如果你是在云服务器上搭环境,除了系统防火墙,还要检查安全组规则有没有放行对应端口。我遇到过有人在云服务器上搭好了,本地浏览器死活打不开9870端口,折腾半天才发现是安全组没配。4. 伪分布式环境搭建:一步一步来,别跳步4.1 下载和解压从Apache官网下载Hadoop的二进制包,注意要下binary版本,不是source版本。下载地址自己搜一下“Apache Hadoop releases”就能找到。下载完之后解压到你喜欢的目录,比如/opt/hadoop或者~/hadoop。我习惯放在/opt下面,因为路径短,后面配环境变量方便。tar -xzvf hadoop-3.3.6.tar.gz -C /opt/ mv /opt/hadoop-3.3.6 /opt/hadoop解压完之后,把Hadoop的bin和sbin目录加到PATH里,方便后面直接敲命令。在~/.bashrc或者~/.bash_profile里加上:export HADOOP_HOME=/opt/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin然后source ~/.bashrc让配置生效。验证方式:hadoop version能输出版本信息就说明PATH配对了。4.2 配置Hadoop的五个核心文件Hadoop的配置文件都在$HADOOP_HOME/etc/hadoop/目录下。伪分布式模式需要改五个文件,我一个个说。第一个:hadoop-env.sh这个文件里要设置JAVA_HOME。找到export JAVA_HOME=那一行,改成你实际的Java安装路径。比如:export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64很多人这里写错路径,导致后面启动时报“JAVA_HOME is not set”或者“Error: JAVA_HOME is incorrectly set”。验证方式:echo $JAVA_HOME输出的路径和这个文件里写的一致,并且该路径下确实有bin/java这个可执行文件。第二个:core-site.xml这个文件配的是Hadoop的全局参数,最重要的是fs.defaultFS,指定HDFS的地址。伪分布式下写成:<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop-node1:9870</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop/tmp</value> </property> </configuration>注意hdfs://hadoop-node1:9870里的主机名要和你之前配的hosts一致。hadoop.tmp.dir是Hadoop的临时目录,默认在/tmp下面,但/tmp重启后可能会被清空,导致NameNode的元数据丢失,所以最好改到一个持久化的目录。第三个:hdfs-site.xml这个文件配HDFS相关的参数。伪分布式下主要配副本数,因为只有一台机器,副本数设成1就行,设成3会一直报“副本不足”的警告。<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/opt/hadoop/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/opt/hadoop/data/datanode</value> </property> </configuration>dfs.namenode.name.dir和dfs.datanode.data.dir分别指定NameNode和DataNode的数据存储目录。不配的话会用默认值,但默认值也在/tmp下面,同样有丢失风险。第四个:mapred-site.xml这个文件配MapReduce相关的参数。伪分布式下要告诉Hadoop用YARN来跑MapReduce:<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.application.classpath</name> <value>$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/mapreduce/lib/*</value> </property> </configuration>mapreduce.application.classpath这个参数在Hadoop 3.x里比较重要,不配的话跑MapReduce任务时可能报ClassNotFoundException。第五个:yarn-site.xml这个文件配YARN相关的参数:<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop-node1</value> </property> </configuration>yarn.nodemanager.aux-services必须设成mapreduce_shuffle,否则MapReduce任务跑不起来。yarn.resourcemanager.hostname指定ResourceManager所在的主机名。4.3 格式化NameNode和启动集群配置改完之后,第一次启动前需要格式化NameNode:hdfs namenode -format这个命令会创建NameNode的元数据目录。注意:格式化只能做一次,如果你后面改了配置想重新格式化,必须先把之前生成的namenode和datanode数据目录删掉,否则会导致clusterID不一致,DataNode起不来。我见过有人反复格式化,最后DataNode死活连不上NameNode,就是因为没删旧数据。格式化成功后,启动HDFS:start-dfs.sh然后启动YARN:start-yarn.sh启动完成后,用jps命令检查进程。正常应该看到NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager这五个进程。如果少了哪个,去对应的日志目录(默认在$HADOOP_HOME/logs/)看错误信息。4.4 验证环境是否正常打开浏览器,访问http://hadoop-node1:9870,这是NameNode的Web UI。能看到Overview页面说明HDFS起来了。再访问http://hadoop-node1:8088,这是ResourceManager的Web UI,能看到集群资源信息说明YARN也正常。然后在HDFS上建个目录测试一下:hdfs dfs -mkdir -p /user/yourname hdfs dfs -ls /能正常列出目录就说明HDFS读写没问题。5. 跑通第一个MapReduce程序:WordCount完整实操5.1 准备输入数据先在本地建一个文本文件,随便写几行英文,比如:hello world hello hadoop hadoop is great hello mapreduce然后把这个文件上传到HDFS:hdfs dfs -mkdir -p /user/yourname/input hdfs dfs -put wordcount.txt /user/yourname/input/用hdfs dfs -ls /user/yourname/input/确认文件上传成功。5.2 运行自带的WordCount示例Hadoop的安装包里自带了一个WordCount的示例jar包,路径在$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar。直接跑:hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /user/yourname/input /user/yourname/output这个命令的意思是:用hadoop-mapreduce-examples这个jar包里的wordcount类,处理HDFS上/user/yourname/input目录下的所有文件,结果输出到/user/yourname/output目录。注意输出目录必须不存在,否则会报“Output directory already exists”。这是Hadoop的一个保护机制,防止你误覆盖之前的结果。5.3 查看运行结果任务跑完后,查看输出:hdfs dfs -ls /user/yourname/output hdfs dfs -cat /user/yourname/output/part-r-00000part-r-00000是Reduce任务的输出文件,r表示这是Reduce阶段的输出。你会看到每个单词和它的出现次数,按字母顺序排列。5.4 理解任务执行过程在任务运行期间,你可以通过ResourceManager的Web UI(8088端口)看到这个应用的执行状态。点进去能看到ApplicationMaster的页面,里面有Map任务和Reduce任务的进度、每个任务的运行节点、耗时等信息。这是理解MapReduce执行流程最直观的方式。整个流程大致是这样的:客户端提交任务到ResourceManager,ResourceManager找一个NodeManager启动ApplicationMaster,ApplicationMaster向ResourceManager申请Container来跑Map任务和Reduce任务。Map任务读取HDFS上的输入分片,处理后输出中间结果到本地磁盘;Shuffle阶段把中间结果按key分发到Reduce任务;Reduce任务汇总后把最终结果写回HDFS。6. 常见问题与排查技巧实录6.1 启动时报“Connection refused”这是最常见的错误之一。症状是执行start-dfs.sh或start-yarn.sh时,日志里出现“Connection refused”或者“Retrying connect to server”。原因通常是SSH免密登录没配好,或者主机名解析有问题。排查步骤:先确认ssh localhost能不能免密登录,如果不能,重新配SSH密钥;如果能,检查/etc/hosts里主机名和IP的映射是否正确,以及Hadoop配置文件里用的主机名是否和hosts里一致。6.2 DataNode启动后马上消失jps看到DataNode进程一闪而过,或者启动后几秒钟就没了。去$HADOOP_HOME/logs/目录下看DataNode的日志,常见原因有两个:一是多次格式化NameNode导致clusterID不一致,解决方法是删掉namenode和datanode的数据目录,重新格式化一次;二是数据目录权限不对,Hadoop进程没有写权限,解决方法是把数据目录的owner改成运行Hadoop的用户。6.3 Web UI打不开进程都起来了,但浏览器访问9870或8088端口打不开。排查顺序:先在服务器上用curl http://localhost:9870看能不能返回内容,如果能,说明是网络或防火墙问题;如果不能,说明服务本身没起来。防火墙问题在Linux上用systemctl status firewalld或ufw status检查,云服务器还要检查安全组。另外注意,Hadoop 3.x的NameNode Web UI端口是9870,不是2.x时代的50070,别搞混了。6.4 MapReduce任务卡在ACCEPTED状态任务提交后一直显示ACCEPTED,不进入RUNNING状态。这通常是YARN资源不够,比如NodeManager的内存配置太小,或者集群资源被其他任务占满了。去ResourceManager的Web UI看集群资源情况,如果Available Memory是0,说明资源不够。可以调大yarn.nodemanager.resource.memory-mb的值,或者等其他任务跑完。6.5 任务报“ClassNotFoundException”跑MapReduce任务时出现ClassNotFoundException,通常是mapreduce.application.classpath没配好,或者jar包里的类路径不对。检查mapred-site.xml里的mapreduce.application.classpath配置,确保包含了$HADOOP_HOME/share/hadoop/mapreduce/*和$HADOOP_HOME/share/hadoop/mapreduce/lib/*。问题现象可能原因排查方法解决方案Connection refusedSSH免密未配或主机名解析失败测试ssh localhost,检查/etc/hosts重新配SSH密钥,修正hosts映射DataNode启动后消失clusterID不一致或目录权限问题查看DataNode日志删数据目录重新格式化,修正权限Web UI打不开防火墙或安全组未放行curl localhost测试,检查防火墙关闭防火墙或放行端口任务卡在ACCEPTEDYARN资源不足查看ResourceManager UI资源状态调大NodeManager内存配置ClassNotFoundExceptionclasspath配置缺失检查mapred-site.xml补全mapreduce.application.classpath提示:每次改完配置文件,都需要重启对应的Hadoop服务才能生效。改HDFS配置重启HDFS,改YARN配置重启YARN。重启命令分别是stop-dfs.sh/start-dfs.sh和stop-yarn.sh/start-yarn.sh。7. 入门之后往哪走:几个值得深入的方向把伪分布式跑通、WordCount跑成功之后,你算是正式入了Hadoop的门。但入门只是起点,后面还有几个方向值得深入。第一个是完全分布式集群搭建,把NameNode、ResourceManager、DataNode、NodeManager分散到多台机器上,理解HA(High Availability)方案怎么配,这是生产环境的基本要求。第二个是自己写MapReduce程序,不要只跑示例,用Java写一个自己的Mapper和Reducer,理解InputFormat、OutputFormat、Partitioner、Combiner这些组件的作用。第三个是HDFS的底层原理,包括NameNode的元数据管理、DataNode的块存储、副本放置策略、读写流程等,这些理解了,后面调优和排查问题会轻松很多。第四个是YARN的资源调度,了解FIFO、Capacity、Fair三种调度器的区别和适用场景。我个人建议的顺序是:先把伪分布式玩熟,然后自己写几个MapReduce程序(比如统计日志里的IP访问次数、计算每个用户的平均消费金额),再搭一个三节点的完全分布式集群,最后再去深入原理。不要一上来就啃源码或者看调度算法,那样容易劝退。动手跑起来、看到结果、遇到问题、解决问题,这个循环才是最快的学习路径。另外说一个我自己的体会:Hadoop的很多设计思想(分而治之、移动计算、副本容错)在后面的Spark、Flink里都能看到影子。所以入门阶段不要只盯着Hadoop的API和配置,多想想它为什么这么设计,这些思想才是真正能迁移到其他技术栈的东西。我见过不少人Hadoop命令敲得很溜,但问他“为什么HDFS的块大小默认是128MB而不是1GB”,就答不上来了。这种只记操作不理解原理的学习方式,遇到新问题就容易卡住。最后再分享一个小技巧:搭建环境的时候,每改一个配置文件就重启一次服务并验证,不要一次性改完所有文件再启动。这样出问题的时候你能快速定位是哪个配置改错了。我当年就是一次性改了五个文件然后启动失败,挨个排查花了半天,后来养成“改一个验一个”的习惯,效率反而高了很多。