1. Hadoop2到底改了什么:不是“更快的MapReduce”这么简单
很多人搜到“hadoop2 介绍使用与集群搭建”这个话题时,真实诉求往往是“赶紧跑起来一个能用的环境”。这个需求我完全理解,但我还是要先泼一盆冷水:如果跳过原理直接抄命令,启动是启动了,接下来改个主机名、调一下内存或者换台机器,你就会彻底不知道从哪里下手。所以先用十来分钟把Hadoop2的骨架看清楚,后面每一步配置才会有方向感。
Hadoop2和Hadoop1最本质的区别,不是“跑得更快”,而是把“资源管理”从“计算模型”里彻底抽离了出来。Hadoop2由三块构成:HDFS负责分布式存储,YARN负责集群资源调度,MapReduce只是运行在YARN上的一个计算引擎。理解了这个结构,你就能明白为什么后来的其他计算框架也能直接跑在同一个集群上,也就能想明白配置文件里为什么总有一堆看似重复的内存参数。
1.1 先分清“存”和“算”:HDFS与YARN各自负责什么
HDFS最容易让初学者误解的地方,是它的“复制+分散”策略。文件被切成默认128MB大小的数据块,每个块默认保存三份副本,并且副本会被尽量放置到不同机器、不同机架上。这不是为了浪费磁盘,而是为了在硬件故障成为常态的分布式环境里保住数据。你可以把HDFS理解成一个公共档案馆:每份重要文件都在不同房间放了三份复印件,某一间房失火或硬盘损坏,另外两间房里的复印件还能用。
YARN则是整个集群的资源调度中心。它管理的是“集群里一共有多少CPU和内存,哪些应用正在用、哪些还没申请到”。MapReduce作业提交上来之后,并不会直接涌向各个节点,而是先向YARN申请资源。YARN同意分配多少资源,任务才能使用多少资源。这个“按需申请、统一分配”的机制,让同一个HDFS集群上并行跑多种计算作业成为可能,这正是Hadoop2比Hadoop1更“现代化”的原因。
另一个容易忽略的点是,HDFS本身不关心你跑什么计算。它只负责文件的切片、副本放置和元数据维护。真正把文件内容读出来、按业务逻辑加工一遍的,是计算引擎。这种“存储与计算分离”的架构,让HDFS成为一个可以长期复用、不会被某一种计算方式绑架的底座。
1.2 YARN的三个核心角色:RM、NM、AM
配置和排错时,你至少要能区分三个缩写:RM、NM、AM。
ResourceManager(RM)是全局管理者,运行在主节点上,负责接收作业请求、分配容器、监控NodeManager的状态。NodeManager(NM)运行在每个从节点上,负责监听RM的指令,启动和销毁容器,并定时上报本机的CPU、内存使用情况。ApplicationMaster(AM)则是某个具体作业的“项目经理”:作业提交后,会在某个节点上启动一个AM进程,由它向RM提出资源申请,再把真正要执行的任务分发给各个容器。
很多奇怪的失败都出在这个机制上。例如,作业一直停留在“ACCEPTED”状态,多半是AM启动不了;任务运行时被反复杀死,多半是容器内存超限。这些问题从界面上只能看到表象,真正的判断还要依赖日志。所以后面我会专门讲“先看哪一层日志”,这是比调参数更重要的排查能力。
我再补充一个生活化类比:RM像物业总台,NM像每层楼的管家,AM像你请来办活动的策划公司。活动方案是策划公司想的,但场地、水电、临时工都是从物业那里申请来的。三者之间任何一环沟通失败,活动都会卡住。
1.3 学习Hadoop2最容易掉进去的三个误区
第一个误区是“把大量小文件直接放进HDFS”。HDFS的元数据由NameNode用内存维护,文件数量、目录数量、数据块数量都会反映在内存占用上。成百上千万的零碎小文件,会先把NameNode内存拖垮,后续读写性能断崖式下降。实际项目中一般要把小文件合并成顺序读的大文件,或者压缩成列式存储格式再导入。
第二个误区是“块越大越快”。块大小只决定HDFS切分的粒度,不等于并行度越高越好。块太大,单个Map任务处理的数据量就大,某个任务一旦拖慢,整个作业就被它拖住;块太小,元数据膨胀,任务数量暴涨,调度成本也上升。默认的128MB适合绝大多数场景,先不要随意改。
第三个误区是“MapReduce是唯一选择”。Hadoop2的资源管理是通用的,数据放好了之后,你可以用SQL引擎做交互式查询,也可以做更复杂的图计算或实时处理。如果只是查一张几GB的过滤表,用MapReduce硬写反而复杂又没有效率。先学会判断“什么场景该用什么”,比多背几个API有用得多。
2. 搭建前的资源规划:宁可小一点,也别让角色分工模糊
我在折腾集群的早期踩过一个很典型的坑:为了省机器,把所有角色都塞进同一台机器,然后又跑到另一台机器上重复同样的操作。结果两台机器既是主又是从,看起来进程都活着,实际读写却一团乱。搭建集群的第一条原则,就是先把节点的角色分清楚,再动手装软件。
学习阶段不追求大集群,三台Linux虚拟机就足够体验完整的分布式流程。常见的划分是:一台作为主节点,跑NameNode和ResourceManager;另外两台作为从节点,跑DataNode和NodeManager。如果你之后还想体验高可用,再额外准备几台机器专门跑协调组件节点和备用NameNode,这个后面会说。
2.1 最少三台机器,每台需要多少内存
内存方面,学习环境每台机器有8GB就够用了,但要注意别同时开太多占用内存的进程。我建议主节点给JVM堆预留4GB以上,从节点给DataNode和NodeManager各留2GB左右。如果是在自己电脑上开虚拟机,先确认宿主机内存够用,别把整台电脑卡死。
硬盘方面,数据目录所在分区不建议和操作系统放在同一块极小的磁盘上,否则一个写满日志的节点可能把数据目录也拖垮。角色划分可以参考下面这张表:
| 节点 | 运行进程 | 建议最低配置 |
|---|---|---|
| 主节点 | NameNode、ResourceManager | 4核CPU / 8GB内存 |
| 从节点1 | DataNode、NodeManager | 2核CPU / 4GB内存 |
| 从节点2 | DataNode、NodeManager | 2核CPU / 4GB内存 |
这个配置跑示例作业没问题,但不要拿生产数据去压测。学习阶段的核心目标是把机制跑通,不是追求吞吐量。
2.2 网络、主机名与SSH免密登录
Hadoop集群对节点之间的网络延迟很敏感,所以节点最好都在同一个内网网段,不要一台在机房、一台在办公室用公网互联。搭建前先用固定的hostname把每台机器命名好,并同步写进所有机器的/etc/hosts。比如规划三个名字:hadoop-master、hadoop-node1、hadoop-node2。配置里尽量用主机名而不是IP,因为换网络环境后IP一变,所有配置文件都得跟着改。
SSH免密登录是启动脚本能够跨机器拉起进程的基础。你需要在主节点生成一对密钥,然后把公钥分发给所有从节点,甚至可以主节点自己也放一份。操作步骤是:在主节点执行ssh-keygen -t rsa生成密钥,然后用ssh-copy-id把公钥依次拷贝到每台机器。完成后从主节点分别ssh到node1、node2,确认不再需要输入密码。这里卡住的话,优先检查防火墙和hosts解析,而不是反复重新生成密钥。
2.3 版本与JDK环境怎么定
这里专门提醒一句:Hadoop2是2.x系列的统称,不要随便在网上下载一个来历不明的二进制包。优先选择主流社区稳定版本,小版本尽量选维护时间较长、参考资料较多的那个。JDK方面,建议统一用JDK 8,不要混用更高版本,因为部分旧版本Hadoop对新JDK的支持并不好。把JAVA_HOME写进主节点的/etc/profile里,同时确认每台机器java -version都能正常输出版本信息。
如果机器上原本装过其他Java版本,或者曾经跑过其他大数据组件,建议先清理干净再开始。版本混用导致的NoClassDefFoundError、UnsupportedClassVersionError这类问题,排查起来比配置本身烦得多。
3. 从伪分布式到真集群:配置文件逐项拆解
机器备好之后有两条路可走:先在本机跑通伪分布式再扩展到多节点,或者直接按多节点配置一次到位。我的建议是,第一次搭建就按多节点集群来配,但先在单台机器上把同样的配置逻辑走一遍。这样出了问题,至少能分清是网络问题还是配置问题。
3.1 安装目录与软链规划
把下载好的安装包解压到/opt目录下,目录名保留版本号。然后建立一个不带版本号的软链接指向它,比如ln -s /opt/hadoop-2.x.x /opt/hadoop。之后所有配置和脚本都引到/opt/hadoop,以后升级版本时只要换软链指向,不用把配置里的路径全部改一遍。
接下来的配置文件都在$HADOOP_HOME/etc/hadoop目录下,重点看六个:hadoop-env.sh、core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml、slaves(部分新版本已经改叫workers)。我建议先把它们备份成带.bak后缀的副本再编辑,这个习惯能救你很多次。
3.2 五个核心XML文件的配置逻辑
第一个是hadoop-env.sh,主要在里面指定JAVA_HOME。不要只依赖系统环境变量,显式写出来更稳妥:
export JAVA_HOME=/usr/local/jdk1.8 export HADOOP_HOME=/opt/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin第二个是core-site.xml,它决定整个集群默认的入口。关键配置是fs.defaultFS和临时目录。fs.defaultFS会告诉所有客户端,默认文件系统是哪一个HDFS集群,主节点的名称可以用主机名:
<property> <name>fs.defaultFS</name> <value>hdfs://hadoop-master:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop/tmp</value> </property>第三个是hdfs-site.xml,配置NameNode的数据目录、DataNode的数据存储目录和副本数。这里的name.dir和data.dir可以配置多个路径并用逗号分隔,相当于给关键数据做多副本备份。学习阶段配置一个路径就行,生产环境建议跨磁盘配置:
<property> <name>dfs.namenode.name.dir</name> <value>/data/hdfs/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/data/hdfs/datanode</value> </property> <property> <name>dfs.replication</name> <value>2</value> </property>副本数这里解释一句:三台节点的集群可以配2副本,也可以配3副本。3副本更接近生产环境,但存储占用更高。学习阶段用2就够了,一台机器挂掉,另一台上还有副本,读写仍能继续。
第四个是yarn-site.xml,主要配置ResourceManager运行在哪台机器,以及NodeManager辅助服务。MapReduce作业通过shuffle从Map端把数据送到Reduce端,这个shuffle辅助服务需要在NodeManager里开启:
<property> <name>yarn.resourcemanager.hostname</name> <value>hadoop-master</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property>第五个是mapred-site.xml。在Hadoop2里,MapReduce不再自己管理资源,而是跑在YARN上,所以这个文件的核心配置是告诉MapReduce框架使用YARN:
<property> <name>mapreduce.framework.name</name> <value>yarn</value> </property>最后是slaves文件,里面列出从节点的主机名,一行一个:
hadoop-node1 hadoop-node2这个文件的命运和hostname绑定:改了主机名却忘了更新这里,或者这里写了IP但hosts里没有对应解析,启动脚本就会发现“找不到节点”。
3.3 第一步格式化,第二步启动,第三步验证
多节点集群的常规流程是:把配置好的整个Hadoop安装目录分发到所有从节点,保持目录结构一致,然后在主节点第一次启动前执行格式化:
hdfs namenode -format格式化只有在第一次搭建时需要执行,或者集群数据已经不重要、想推倒重来的时候才执行。格式化会清空NameNode上的元数据信息。如果你已经往集群里写了重要数据,执行格式化会把“数据入口”全部重置,数据本身可能还在DataNode上,但文件记录已经找不到了。所以格式化之前务必三思。
启动命令按顺序执行:
start-dfs.sh start-yarn.sh如果想一条命令同时启动全部进程,可以执行start-all.sh,但建议不要一开始就用,因为不利于定位问题。启动后每台机器执行jps,看到对应进程才算成功。主节点应该有NameNode和ResourceManager,从节点应该有DataNode和NodeManager。浏览器界面里,HDFS和YARN都有对应的Web页面,可以从启动日志里看到访问地址和端口。
提示:我第一次搭的时候,习惯启动完就马上跑任务,结果经常因为进程还没完全注册完而报错。正确做法是启动后等一两分钟,再用jps确认进程,最后用命令行上传一个文件测试读写,确认无误再提交作业。
4. 跑通第一个任务:上传数据到HDFS并运行MapReduce作业
集群起来的标志不是进程都活着,而是能正常读写数据、能提交一个作业并看到结果。这一节我们就以最经典的词频统计为例,把整个使用链路走一遍。
4.1 命令行操作HDFS的基本姿势
HDFS的命令行大多以hdfs dfs开头,风格和Linux命令很接近。先创建目录,把测试文件上传:
hdfs dfs -mkdir /input hdfs dfs -put ./test.txt /input/test.txt hdfs dfs -ls /input准备测试文件时,我一般会放几段不重复的英文句子,内容越多样越好。注意,如果文件只有几百字节,它在HDFS上只占用一个块的空间,对测试来说没问题,但不要用这个结果去推断生产环境的性能。
4.2 用自带示例Jar包跑WordCount
Hadoop发行版自带的示例Jar包,路径一般在$HADOOP_HOME/share/hadoop/mapreduce/目录下,文件名类似hadoop-mapreduce-examples-版本号.jar。运行词频统计的命令如下:
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-版本号.jar wordcount /input /output注意,输出目录/output必须是不存在的。如果上一次作业已经生成过,需要先删除:hdfs dfs -rm -r /output。原因是HDFS上的输出目录由MapReduce框架负责创建,如果它已经存在,框架会担心你误覆盖旧数据,直接报错。这是新手最容易踩的坑。
作业提交后,终端会持续打印进度信息,看到类似“Map 100% Reduce 100%”以及Job complete这样的输出,就说明执行成功。然后用hdfs dfs -cat /output/part-r-00000查看结果。
4.3 从YARN界面反推任务的资源使用
跑完作业后,去YARN的Web界面看一眼,刚才的作业已经执行结束,界面上能看到这个作业申请了多少容器、每个容器多少内存。这个信息非常有用。比如你发现大量任务只申请了默认的1GB内存,而机器本身内存很充足,那就可以在mapred-site.xml里调高mapreduce.map.memory.mb和mapreduce.reduce.memory.mb。
反过来,如果任务频繁因为内存被杀掉,就去调低单个容器的内存,或者增加NodeManager可用内存。我自己一般会同时开两个终端:一个终端提交作业,另一个终端盯着ResourceManager的日志。日志比界面更能暴露问题,尤其当一个任务卡在“ACCEPTED”或“RUNNING”状态不动时,日志里的资源申请记录能帮你判断到底是YARN分配不出资源,还是ApplicationMaster启动失败。
5. 进阶配置:从高可用到资源调优,集群才真正敢上生产
如果只是学习,第4节就可以停下来了。但如果你准备把集群留给团队用,有一些配置必须在数据变多之前提前做完。这些配置不会让你的示例作业跑得更快,但会决定集群在面对故障和真实负载时还能不能稳住。
5.1 单点故障是Hadoop2集群的头号隐患
非HA模式下,NameNode是整个HDFS的元数据中心。它挂了,意味着所有客户端都无法找到文件的存储位置,集群对外表现为“文件系统不可用”。很多人以为NameNode进程重启就能解决,但重启需要时间恢复元数据,这个时间窗口里业务完全停摆。对于只有一个NameNode的小集群,这个风险可能暂时可以接受;但生产环境至少需要两台NameNode组成主备。
Hadoop2的HA方案需要引入JournalNode集群来同步主备NameNode之间的编辑日志,同时用协调组件辅助完成自动故障切换。JournalNode一般建议部署奇数台,比如3台,这样可以容忍少数节点故障。我自己的实践体会是:在集群还不稳定的时候,不要急着开自动故障切换,先用手动切换把整个机制摸熟,再交给自动切换。主备切换看起来只是“多配置几个节点”,实际上涉及网络分区、脑裂防护、JournalNode写延迟等细节,不是改两个配置就能一劳永逸的。
5.2 按内存资源改好YARN调度参数
YARN的内存配置是整个集群最容易出错的地方。先说原则:NodeManager上报的可用内存,不能大于机器实际物理内存减掉操作系统和其他常驻进程后的剩余量;集群所有NodeManager上报内存之和,是ResourceManager可以分配的总量。如果一个NodeManager上报了16GB,但这台机器本身只有8GB内存,那它启动容器时就会出现各种OOM。
举例来说,一台16GB内存的从节点,操作系统预留2GB,DataNode预留2GB,NodeManager可以分配约10GB。如果单个容器默认是1GB,那么这台机器最多同时跑8个任务,还要留一点给系统突发使用。你可以在yarn-site.xml里做类似的规划:
<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>10240</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>4096</value> </property>第二个参数的意思是单个容器最大不能超过4GB。这样既不会因为容器太大把某台机器打满,也不会因为默认值太小导致大任务跑不动。调整之后,记得在mapred-site.xml里同步调整Map和Reduce任务的内存上限,否则YARN分配了容器,但MapReduce任务自己不认可,依然会失败。
5.3 上线前必须做的三件小事
第一,把日志聚合打开。YARN默认情况下,作业运行完,日志就散落在各节点上,你想排查一个已经结束的任务,得挨个节点找日志。开启日志聚合后,日志会被上传到HDFS统一存储,用yarn logs命令就能查看。第二,设置合理的副本数。生产环境建议至少3副本,并确保三个副本分布在尽可能不同的机架上。第三,定期清理无用数据目录和临时文件,不要等到磁盘写满才想起来。
这三件事都不复杂,但很多人直到集群出问题才想起来做。我见过一个例子,某台节点系统盘被日志填满,DataNode进程反复重启,排查了大半天才发现是日志清理策略没配好。所以这种“小事”,反而是生产集群最重要的防线。
6. 运行过程中踩过的坑和排错路径
最后分享几个被反复问到的实际问题。它们与Hadoop2本身的稳定性关系不大,基本都是配置和使用方式造成的。我把排查思路写出来,你照着走一遍,比自己瞎试半天有效得多。
6.1 集群一启动就进入安全模式是怎么回事
HDFS刚启动时,因为DataNode还没把数据块信息上报完,NameNode会进入安全模式,此时文件系统只能读不能写。等待一段时间后会自动退出。但如果DataNode上报太慢,或者某个DataNode一直起不来,安全模式就会卡住。先看每个节点jps确认DataNode进程是否在,再用hdfs dfsadmin -report查看块上报情况。
如果只是测试环境,也可以手动执行hdfs dfsadmin -safemode leave退出,但生产环境不要这样硬来。安全模式存在的意义是让NameNode先收集足够多的块信息,确认数据冗余度正常后再开放写入。强制退出容易掩盖数据块缺失的问题,等真正需要读某个文件时才发现数据已经丢了。
6.2 任务反复失败,先去查容器日志
很多MapReduce作业失败的原因,不是业务代码逻辑问题,而是容器资源不够。比如数据量大时Map任务需要的内存超过容器上限,就会看到Container killed by ApplicationMaster这样的提示。这时候不要去改业务代码,而是先把mapreduce.map.memory.mb调大一点,或者把yarn.scheduler.maximum-allocation-mb放宽,再看结果。
排查顺序应该是:先看YARN界面里这个作业的失败原因,再去看具体节点的NodeManager日志,最后才是看MapReduce任务自己的stdout和stderr。很多新手的习惯是一上来就翻最后一段任务日志,结果绕了远路。因为任务日志里往往只有业务异常,看不到资源分配、进程退出这一类系统层面的信息。
6.3 磁盘写满和日志爆掉的教训
Hadoop集群一旦磁盘写满,DataNode并不能直接对外报告“磁盘满”,而是表现为写数据超时、心跳中断、副本复制失败。这个问题很隐蔽。我有一次排查了很久,最后才发现是某台机器上/var/log目录被错误日志写满。所以建议从一开始就在监控里盯三项指标:每个数据目录的磁盘剩余空间、每台机器系统盘使用率、YARN聚合日志目录大小。偶尔手动df -h看一眼,比任何调优都重要。
最后说一句个人体会:搭建Hadoop2集群不是什么玄学,把“角色分工、配置命名、日志位置、资源上限”这四件事想清楚,后续使用会很顺。很多人卡在搭建阶段,其实不是因为步骤复杂,而是因为没有理解每一步在做什么。如果你今天第一次搭,建议按这篇文章的顺序走,不要跳步,尤其不要把格式化和启动顺序搞反。在单机伪分布式上先跑通一次,再扩展到多节点,你会发现自己对分布式系统的那层“恐惧感”基本消失了。