1. 为什么网上教程一堆,照着做还是起不来:先把集群的“底座”盘清楚
如果你在Ubuntu上搭过Hadoop集群,大概率经历过这种场面:跟着一篇教程从头敲到尾,start-dfs.sh一执行,NameNode起来了,DataNode死活不亮;或者三台机器都执行完了,Web页面一打开,live nodes只有1个。然后你开始怀疑人生,觉得是不是自己哪一步敲错了。
其实大多数情况下,不是你敲错了,而是教程没告诉你“为什么”。网上写CentOS搭建的教程一抓一大把,但Ubuntu用户用起来总觉得隔着一层——包管理器不一样、防火墙命令不一样、目录习惯不一样,甚至/etc/hosts的写法在某些云主机上还会被覆盖。这篇文章我不打算复刻一篇“命令清单”,而是把你从0到1搭建一套三节点Hadoop集群时,真正需要理解的东西拆开讲。它适合刚把大数据方向摸了个边、准备自己动手练手的学习者,也适合工作中需要在Ubuntu上快速交付一套测试环境的工程师。
我这边反复清理环境重新搭过几轮,踩过的问题基本都是相似的。把这篇文章看完,你大概可以在一到两小时内得到一个能稳定跑起来的三节点集群,并且知道每个配置项是干什么的,出了问题该从哪里下手查。我们以Ubuntu 22.04 LTS、Hadoop 3.3.6、OpenJDK 8作为基准环境来展开。
先明确一件事:Hadoop集群本身不神秘,它本质上是“多台机器各司其职、通过网络协调工作”。一台机器当NameNode做“大脑”,记录整个文件系统里每个文件被切成多少块、每一块存在哪台机器上;另外几台机器当DataNode做“仓库”,真正存放数据。再加上ResourceManager和NodeManager负责计算任务的调度与执行。理解了这一点,后面所有配置都只是在回答同一个问题:告诉每台机器,你是谁、你能干什么、你该听谁的。
1.1 角色规划:三台机器分别该做什么
最经典的规划是三节点集群:一台master,两台slave。我这里用hostname命名,按顺序是node01(master)、node02、node03。
- node01:NameNode + SecondaryNameNode + ResourceManager
- node02:DataNode + NodeManager
- node03:DataNode + NodeManager
实际资源允许的情况下,建议给node01至少4GB内存,node02和node03至少2GB。如果机器资源很紧张,1GB内存也能勉强跑,但YARN任务和GC很容易把节点拖死,后面排查内存问题会占用你非常多时间。
有人会问,master节点上要不要也放DataNode?测试环境放上去没毛病,但三台机器还有一个常用变体:把master也作为DataNode,这样三台都是“计算+存储”节点,HDFS副本数可以设置为3。这个方案能让文件系统更“满”,但对机器资源要求更高。我建议第一次搭集群就老老实实两个DataNode,副本数设为2,跑通之后你想怎么改都可以。
1.2 版本选型:为什么要选Hadoop 3.3.x + JDK8
版本选型会影响整个搭建的顺利程度。Hadoop 3.x相比2.x最大的变化是支持了HDFS联邦、NameNode热备的简化,以及默认端口从50070换成了9870。很多老教程还在讲50070端口,你在3.x上怎么访问都打不开页面,这就是版本不对应造成的典型问题。
JDK方面,Hadoop 3.3.x官方支持Java 8和Java 11,但实际经验告诉我,OpenJDK 8是最稳的。JDK 11在某些Hadoop版本上会报IllegalArgumentException之类的JVM参数问题,JDK 17更是踩坑重灾区。不要问“能不能用更新的JDK”,能用不代表稳,集群这东西稳定优先。
Ubuntu版本我推荐22.04 LTS或者20.04 LTS。太新的非LTS版本(比如23.10)的GLIBC库比较激进,虽然Hadoop是纯Java程序影响不大,但系统源的兼容性会让你在装包阶段就烦。生产环境求稳,LTS永远是第一选择。
1.3 目录规划:不要把所有东西都塞进根目录和/tmp
集群搭完最怕什么?重启一次,元数据没了。这个坑十有八九和目录规划有关。
Hadoop默认会把数据写到/tmp/hadoop-*下面,而/tmp在某些系统上重启会被自动清理。所谓“重启后丢数据”,多半就是这个原因。所以从第一天起,就要把Hadoop的数据目录规划到一个独立的磁盘路径。我习惯用:
- 软件目录:
/opt/hadoop - 元数据目录:
/data/hadoop/name - 数据块目录:
/data/hadoop/data - 临时文件目录:
/data/hadoop/tmp
这四个目录在配置阶段会反复被用到,先想清楚,后面就不会手忙脚乱。另一个容易被忽略的点是:DataNode的数据目录最好挂在与系统盘不同的物理磁盘上,否则系统日志一多,磁盘一满,所有节点都会跟着出问题。虚拟机测试环境无所谓,物理机上尽量遵守这个原则。
另外创建这些目录时,要记得把属主改成你用来跑Hadoop的系统用户。我在实际搭建中会创建一个专门的用户hadoop,避免直接用root跑Hadoop,后面启动脚本和日志权限问题会少一大半。
2. 三台Ubuntu主机的基础配置:验证一次比盲目复制重要
Hadoop集群搭建有一句大白话:三分配置,七分通信。通信的根基是三台机器能够互相通过主机名访问、通过SSH免密连接。这一节做的事情看起来琐碎,但每一件都值得验证到位。我见过太多人SSH免密没配上就直接启动集群,结果集群进程启动时一直要求输密码,或者DataNode因为连不上NameNode而反复启动失败。
2.1 修改主机名和hosts映射
第一步,给每台机器设置独立主机名。Ubuntu上最简单的方法是使用hostnamectl:
sudo hostnamectl set-hostname node01然后编辑/etc/hosts,把三台机器的内网IP和主机名对应关系写进去。假设三台机器的地址分别是192.168.1.10、192.168.1.11、192.168.1.12:
192.168.1.10 node01 192.168.1.11 node02 192.168.1.12 node03这里有一个很重要的细节:不要只改master的hosts,三台机器都要写同一份映射。因为DataNode启动时会通过主机名反查NameNode,如果node02上不知道node01是谁,它的注册请求根本无法发出。很多新手只改了master,结果所有从节点全部启动失败,报错信息却千奇百怪。
还有一个云环境常见坑:在某些云主机或带NetworkManager的系统里,DHCP或NetworkManager可能会重写/etc/hosts。配置完最好重启网络或重启机器后再次确认hosts没有被改动。否则集群可能当时能跑,重启后又“失联”。
2.2 SSH免密登录:从node01出发,信任所有节点
Hadoop的启动脚本是在master节点上执行的,脚本需要通过SSH去连每一台机器并远程拉起进程。如果每次都要求密码,集群就只能干瞪眼。
配置方式很简单,在三台机器上各自生成密钥,然后把公钥分发到所有机器的authorized_keys里:
ssh-keygen -t rsa -b 4096 -P "" -f ~/.ssh/id_rsa ssh-copy-id node01 ssh-copy-id node02 ssh-copy-id node03每条ssh-copy-id都会要求输入对应用户的密码,输入一次即可。配完之后,必须做一次完整的验证:在node01上依次执行ssh node01、ssh node02、ssh node03,确认三台都能不再输密码直接登录进去。很多教程只写了“配好了”,没有让你验证,这里我特意强调——这一步不验证,后面的所有故障排查都会多一层迷雾。
如果你跑了ssh-copy-id之后仍然提示要密码,大概率是~/.ssh目录权限或authorized_keys文件权限不对。SSH对私钥和公钥文件的权限非常敏感,建议执行:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keysUbuntu上还要注意,如果开启了SELinux或者额外的SSH加固配置,可能需要检查sshd_config中的PubkeyAuthentication是否被设置为yes。一般默认安装不需要动,但值得知道有这个开关。
2.3 JDK安装与JAVA_HOME配置
Hadoop是Java程序,所以每台机器都要装JDK。Ubuntu上安装OpenJDK 8很简单:
sudo apt update sudo apt install openjdk-8-jdk -y装完之后确认版本:
java -version此时JAVA_HOME不一定被自动设置。我建议在所有节点的~/.bashrc末尾加上:
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$PATH:$JAVA_HOME/bin然后执行source ~/.bashrc。这里要提醒的是:JAVA_HOME的路径如果不对,Hadoop的启动脚本会在找Java的时候失败。一个快速判断方法是执行which javac,把结果再往上一级一层层推,找到实际安装路径。不同Ubuntu版本上OpenJDK的安装目录可能不同,别直接复制网上的路径,要自己确认一遍。
2.4 时钟同步和防火墙,这两个小东西能给你大惊喜
集群节点之间通信依赖网络,但如果各节点的系统时间差太多,Kerberos场景或者某些RPC通信就会出问题。测试环境时间差异不大的话,影响不明显,但如果你在虚拟机里折腾,宿主机休眠导致虚拟机关机过一段时间再恢复,时间可能偏出几分钟。建议至少开启系统自带的systemd-timesyncd服务:
sudo timedatectl set-ntp true sudo timedatectl status防火墙是另一个容易被忽略的点。Ubuntu默认的UFW是关闭状态,但有些最小化安装或者云镜像会默认开启。为了避免排查半天才发现是防火墙把端口挡了,建议测试阶段直接关闭或不安装UFW:
sudo ufw disable如果你必须在开防火墙的环境下跑集群,需要放行以下端口的通信:NameNode RPC端口9000、NameNode Web UI端口9870、DataNode通信端口9864、ResourceManager Web UI端口8088、YARN节点管理器端口8042等。但测试阶段,我强烈建议先关掉防火墙,等集群稳定了再研究最小化放行策略。不要在一开始就给自己增加变量。
3. 五个核心配置文件逐一拆解:每个参数背后都是一个故障
Hadoop的配置逻辑是“分布式的,但配置要统一”。也就是说,配置文件编写出来后,要把node01上的一套配置原封不动地分发到所有节点,再根据每台机器的角色决定启动哪些进程。这个模式下,文件的同步和一致性比单个文件的正确性更重要。下面这五个文件是整个集群的灵魂,我按“为什么是这个值”的思路来一一说明。
3.1 core-site.xml:先给集群定个“中央地址”
core-site.xml是Hadoop的核心配置。最关键的是fs.defaultFS,它决定了整个HDFS的“中央入口”在哪里。
<?xml version="1.0"?> <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node01:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>fs.defaultFS的值告诉所有Hadoop组件:“你连接的就是node01:9000这台机器的HDFS”。9000是NameNode的RPC通信端口。如果你自己机器上的端口被占用,或者有其他服务占用了这个端口,NameNode会直接启动失败。所以规划端口也是一门学问,测试时尽量保证端口干净。
hadoop.tmp.dir就是前面反复强调的目录规划落地的位置。Hadoop的很多默认临时数据都会放在这个基础目录下面。如果这个目录不存在,NameNode启动时可能报错,所以配置完最好先手动创建它并设置好权限。
3.2 hdfs-site.xml:决定你的数据“放哪里、存几份”
这个文件直接控制HDFS的存储行为。核心配置项有三个:
<property> <name>dfs.namenode.name.dir</name> <value>file:///data/hadoop/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///data/hadoop/data</value> </property> <property> <name>dfs.replication</name> <value>2</value> </property>dfs.namenode.name.dir是NameNode存放元数据(即文件与数据块的对应关系)的目录。dfs.datanode.data.dir是DataNode存放真实数据块的目录。这两个路径都必须确保权限正确,否则进程会因为连写文件都做不到而启动失败。
dfs.replication表示每个数据块保存几个副本。这里设置为2,因为我们的集群有两个DataNode。如果设为3,而集群只有2个DataNode,数据块会一直处于Under-Replicated状态,Web页面上会看到提示但集群还能运行。一个经验是:副本数不要超过集群DataNode数量,否则会持续产生副本复制任务,白白消耗网络带宽。
在这个文件中还有几个可选配置值得关注。比如dfs.namenode.secondary.http-address,默认是0.0.0.0:9868,如果你的SecondaryNameNode和NameNode分置在不同机器,需要把这个地址指向对应机器。我们用三节点小集群,SecondaryNameNode默认与NameNode同机,这个配置通常不用改。
3.3 yarn-site.xml:让资源调度器认识每台机器
YARN负责计算资源的调度。ResourceManager相当于“调度中心”,NodeManager是每台机器上的“资源管家”。yarn-site.xml的核心配置如下:
<property> <name>yarn.resourcemanager.hostname</name> <value>node01</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>2048</value> </property>yarn.resourcemanager.hostname要指向node01。yarn.nodemanager.aux-services设置的是NodeManager辅助服务,这里必须配置为mapreduce_shuffle,否则后续跑MapReduce作业时,Shuffle阶段的数据传输会直接失败,报错信息通常是“Shuffle failed”之类的字样。
内存配置是另一个高频出问题的点。yarn.nodemanager.resource.memory-mb表示每台NodeManager可以分配的总内存,我这里给2048MB,因为你如果机器只有2GB内存,再往上配就会导致NodeManager启动失败或YARN任务频繁崩溃。yarn.scheduler.maximum-allocation-mb表示单个Container最大可申请内存,一般不要超过NodeManager总内存。理论上这两个值要配合容器数量精心计算,但测试集群给个2GB,起个WordCount验证一下流程完全够用。
还有一个折腾过我的点:如果ResourceManager和NodeManager不在同一套配置下启动,比如node02上把yarn.resourcemanager.hostname写成了自己,NodeManager会一直找本机的ResourceManager,结果当然是注册不上。配置文件统一的必要性在第4节里会反复出现。
3.4 mapred-site.xml:告诉MapReduce“用YARN跑”
在Hadoop 2.0之后,MapReduce的调度框架可以是“经典MROnYARNMode”之外的yarn,这是最常规最流行的选择。mapred-site.xml里最关键的配置是:
<property> <name>mapreduce.framework.name</name> <value>yarn</value> </property>就这么一行。如果这个配置缺失,提交MapReduce任务时会直接跑在本地模式,看起来像是“能跑”,但任务运行Fail或者数据根本不走HDFS,很容易造成误导。在Hadoop 3.x里,这个文件在$HADOOP_HOME/etc/hadoop/目录下,默认不叫mapred-site.xml而是模板文件,需要自己创建。
这里还可以加一个保险配置,解决Hadoop 3.3.x和YARN辅助依赖的classpath问题。部分环境在跑MapReduce时会出现找不到mapreduce.application.classpath的报错,因为默认classpath没包含Hadoop的一些jar包路径。如果遇到这种情况,可以在配置里加上:
<property> <name>mapreduce.application.classpath</name> <value>$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/mapreduce/lib/*:$HADOOP_HOME/share/hadoop/common/*:$HADOOP_HOME/share/hadoop/common/lib/*:$HADOOP_HOME/share/hadoop/hdfs/*:$HADOOP_HOME/share/hadoop/hdfs/lib/*:$HADOOP_HOME/share/hadoop/yarn/*:$HADOOP_HOME/share/hadoop/yarn/lib/*</value> </property>3.5 workers文件:数据节点清单
在Hadoop 3.x中,master节点上有一个workers文件,用来声明哪些机器是DataNode和NodeManager。文件位于$HADOOP_HOME/etc/hadoop/下,内容很简单:
node02 node03这里有三个易错点:第一,workers文件不要写node01,除非你想把master也作为DataNode运行;第二,文件里不要有空格缩进和多余字符;第三,Hadoop 3.x用workers,老教程里说的slaves文件已经被废弃,如果你从旧版本升级过来,一定要改文件名并重新分发。
配置文件的同步原则很简单:在node01上把配置写好后,用scp分发到所有节点:
cd /opt/hadoop/etc/hadoop/ scp core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml workers node02:/opt/hadoop/etc/hadoop/ scp core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml workers node03:/opt/hadoop/etc/hadoop/一定要注意,分发后每台机器上需要单独调整的只有少量以本机身份为变量的配置(比如后续开启HA时才用到的dfs.namenode.rpc-address),我们这套规划里所有配置完全一致,没有任何每台机器需要单独修改的地方。一旦发现某台机器启动后的行为和别的机器不同,先检查它的配置是否一致,而不是去改那台机器的配置。
4. 首次启动与功能验证:格式化不仅是个仪式,还是排查窗口
当所有基础配置完成后,就进入让人既期待又紧张的启动环节。这一节流程走得稳,你就能拥有一套可用的集群。我会故意把“格式化”这一步拆细一点,因为它引发的故障排起来让人头疼。
4.1 格式化NameNode:为什么重新格式化前一定要清数据目录
在首次启动HDFS之前,需要在node01上格式化NameNode。格式化的本质是创建一个空的元数据存储结构,同时生成一个clusterID。后续所有DataNode在启动时,会拿自己的clusterID与NameNode身上的做比对,不一致就会被拒绝注册。
hdfs namenode -format执行完毕后,观察输出中是否有successfully formatted字样。等你第一次真正经历重搭集群的场景,就会体会到“格式化之前先清空数据目录”这条规则的重要性。如果你之前启动过集群,某天突然觉得“我重新格式化一下试试”,结果大概率是DataNode起不来,因为DataNode那边还保留着旧clusterID。解决方案是:把所有节点上dfs.datanode.data.dir目录的内容清空,把NameNode机器上dfs.namenode.name.dir目录的内容也清空,然后再格式化。
我遇到过一位同事,为了清这个数据目录,把/data整个目录rm -rf了,结果把其他服务的数据也删了。所以清理时要精准:只清理name和data这两个Hadoop专用目录里的内容,目录本身保留。
还有一个值得提的操作细节:格式化命令要在HADOOP_HOME环境变量配置正确之后执行。如果你执行hdfs命令提示找不到命令,说明PATH没配好,去检查.bashrc里的环境变量。
4.2 按顺序启动HDFS和YARN:不要一次全启动
很多新手习惯直接执行start-all.sh,这个脚本现在已经不推荐使用了。正确的做法是分开启动:
start-dfs.sh start-yarn.sh在node01上执行这两条命令。start-dfs.sh会读取workers文件,通过SSH到node02和node03上拉起DataNode进程。start-yarn.sh则负责启动ResourceManager(在node01上)和NodeManager(在node02、node03上)。
启动过程会在终端打出日志,建议仔细看一眼输出,不要直接关掉终端。尤其是当输出里出现Permission denied或者Could not resolve hostname时,不要继续往下走,先解决ssh和hosts的问题。如果启动过程没有明显报错但内心没底,可以在每台机器上执行jps命令检查Java进程:
- node01应该有:
NameNode、SecondaryNameNode、ResourceManager - node02、node03应该有:
DataNode、NodeManager
jps的输出是判断集群是否正常的最快方式。如果哪个进程缺失,去看对应机器的Hadoop日志目录:$HADOOP_HOME/logs/。日志文件命名里有进程名,比如hadoop-hadoop-datanode-node02.log。打开日志末尾,90%的故障原因都在那儿明明白白写着。
4.3 通过Web UI确认集群“活着”
集群启动成功后,用浏览器访问:
- HDFS界面:
http://node01:9870,能看到NameNode状态、DataNode列表、文件系统概览 - YARN界面:
http://node01:8088,能看到ResourceManager状态、节点列表、运行中的应用
第一次打开9870页面,看到Live Nodes为2,说明HDFS侧一切正常。如果Live Nodes是0,优先检查DataNode日志里的clusterID匹配错误。如果8088页面里节点列表为空,检查NodeManager日志里的ResourceManager连接信息是否指向了node01。
如果浏览器无法访问,首先确认node01上的防火墙是否放行对应端口,其次确认你是不是用node01这个主机名访问的。有的环境下,本机无法解析自己绑定的主机名,换localhost访问Web UI通常能成。
4.4 用实际文件测试上传和副本分布
集群启动成功后,不要急着欢呼,先做一个端到端验证。在node01上执行:
hdfs dfs -mkdir -p /test hdfs dfs -put /etc/hosts /test/ hdfs dfs -ls /test/能看到文件出现以后,可以再确认一下文件被拆分成了几个块、存到了哪些DataNode上:
hdfs fsck /test/hosts -files -blocks -locations如果副本数为2,fsck输出里同一个Block ID应该对应两个DataNode地址。这一步是验证你的副本策略真的生效。测试环境里很多人忽略了这道检查,直到生产环境出现数据丢失才开始追查副本配置——这是不应该的。
随后可以提交一个简单的MapReduce任务来验证YARN链路:
hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /test/hosts /test/output任务跑完后,执行:
hdfs dfs -cat /test/output/*能看到词频统计结果,说明从HDFS存储到YARN调度到MapReduce计算的全链路已经贯通。
5. 集群跑起来之后的魔鬼细节:稳定运行比搭起来更考验功夫
一套集群从“能启动”到“能稳定跑”,中间还隔着一堆细节。这一节把我在实际使用中遇到最多的三类问题拿出来逐一拆解,每一条都对应着真实的故障场景。
5.1 DataNode总是消失:先查clusterID而不是重装
集群刚搭好那阵子,最容易出现的诡异情况是:今天DataNode还正常,重启之后DataNode就起不来了。日志里最常见的是compatibility或者Incompatible clusterIDs相关报错。
原因我在第4节已经铺垫过:DataNode的data目录里保存了它第一次启动时记录的clusterID。如果NameNode被重新格式化,它的clusterID变了,而DataNode还守着旧值,两边就谈不拢。解决办法有三条路:
- 把DataNode的
data目录下拉的VERSION文件里的clusterID手动改成NameNode的最新值(适合不想丢数据目录的情况)。 - 彻底清除所有DataNode的
data目录内容,重启DataNode让它重新注册(适合测试环境)。 - 全都不要手动改,格式化之前就想清楚:格式化NameNode的代价是所有DataNode都需要“重新认亲”。
我个人的习惯是,在测试阶段永远不保留旧数据,直接走第2条路。在生产没搭建起来之前,最好用的策略就是“重来一步到位”,别和clusterID较劲。
5.2 YARN内存设置不当导致Container崩溃
NodeManager的内存和CPU配置,和你跑的任务类型紧密相关。很多人跑WordCount时一切正常,一换成数据量大一点的任务就频繁报错,错误信息里带着Container killed或Resource manager unable to allocate resources。原因基本就两个方向:
yarn.nodemanager.resource.memory-mb设置得过大,超过了机器实际可用内存。NodeManager会硬着头皮启动Container,结果Container占用内存超出物理内存,进程被系统杀掉。yarn.scheduler.maximum-allocation-mb设置得过小,任务需要的内存超过了这个上限,资源申请一直被拒绝。
最简单的做法是:先看机器物理内存free -h,再把yarn.nodemanager.resource.memory-mb设为物理内存的60%到80%,yarn.scheduler.maximum-allocation-mb设为略小于该值。比如2GB机器,NodeManager配1600MB,Container上限配1500MB,留一些内存给系统本身和HDFS进程。这个比例不是公式,但是足够让测试集群稳定运转。等你真正做生产调优,再按Container数量和任务特征去精细化也来得及。
5.3 重启集群的正确姿势:顺序和清理都别乱
我见过太多人在需要重启集群时,直接关闭所有虚拟机,结果下次开机后各种进程状态错乱。正确的重启顺序是:先关计算任务,再关YARN,最后关HDFS;启动顺序相反。也就是说,最稳的重启操作如下:
# 在node01上执行 stop-yarn.sh stop-dfs.sh然后按第4节的启动顺序再来一遍:start-dfs.sh、start-yarn.sh。这里也要提一下,如果某台机器上的NodeManager进程僵死,直接执行start-yarn.sh可能会提示端口已占用,这时候去那台机器上kill -9对应进程后,再从node01上启动一次即可。
5.4 日志是你最好的排错工具,别放过每一行WARN
最后强烈建议你养成一个习惯:每次启动完集群、发现异常,都到$HADOOP_HOME/logs目录里看对应进程的日志。日志文件以hadoop-用户名-进程名-主机名.log的方式命名。打开日志,如果你看到ERROR,一定看看它所属的上文和堆栈;如果你看到WARN,也别急着跳过。比如HDFS日志里常见的:
WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Problem connecting to server: node01/192.168.1.10:9000这一行直接把问题指向了网络连通性。顺着这个方向查防火墙、查hosts、查NameNode进程是否存活,十分钟内就能定位问题。相比之下,如果你不看日志而在配置文件里反复试错,一头扎进去可能几个小时出不来。
6. 集群搭建后的下一步:从“能跑”走向“好用”
一套集群能稳定跑起来,其实只是大数据之旅的开始。从“能跑”到“好用”,个人实际使用中的体会分享几条。
第一,给集群做一个简单的“体检清单”。每次重启完,按顺序检查:jps进程是否齐全、9870的Live Nodes数量、8088节点列表状态、上传一个1MB的测试文件并用fsck确认块的副本位置。这套流程已经成为我的肌肉记忆,一套五分钟检查,胜过排查一小时的故障。
第二,针对机器资源有限的情况,考虑通过Linux的资源控制工具给每个进程设置内存上限,防止Hadoop进程把系统内存吃光。小型测试集群里Hadoop的Java进程默认内存可能超出你的预期,用free -h看一下实际占用你就明白了。
第三,如果你的集群是用虚拟机搭建的,记得给每台虚拟机关闭自动休眠和屏幕节能,避免虚拟机的时钟在挂起期间走偏,也避免网络中断造成的DataNode掉线。很多“集群运行了好几天没动,某天突然全挂了”的情况,其实只是宿主机在凌晨发生了一次休眠。
第四,考虑给NameNode的元数据目录增加冗余备份。HDFS里文件丢了可以容忍,但NameNode的元数据如果损坏,整个文件系统的目录结构都会无法重建。哪怕只是写个cron定时把/data/hadoop/name打包拷贝一份到其他节点,也能给你的集群多一层保险。
最后想说,在搭建这套Ubuntu集群的过程中,笔者从“照着教程敲命令”到“看懂每一个配置项的作用”,收获最大的一刻,其实是第一次靠自己判断问题、看日志、修复集群的时候。用这套思路走下去,你搭出来的不只是三台机器上的一组进程,而是一套自己心里有底的系统。