☰
华为云Hadoop伪分布式安装实战指南
2026/10/21 7:09:49 网站建设 项目流程

1. 项目概述:为什么从伪分布式开始学Hadoop,而不是直接上集群?

“华为云hadoop伪分布式安装学习笔记(一)”这个标题里藏着一个非常务实的起点——它没写“高可用集群部署”,也没提“PB级数据处理实战”,而是老老实实落在“伪分布式”和“学习笔记”上。这恰恰是绝大多数人真正该走的第一步,但偏偏也是最容易被跳过的一步。我带过不少刚接触大数据的开发者、运维同学,甚至某高校实验室的研究生,上来就想搭三节点集群、配YARN高可用、对接OBS做数据湖,结果连hdfs namenode -format报错都看不懂,更别说/var/log/hadoop-hdfs/里那堆日志到底在说什么。伪分布式不是“简陋版”,它是Hadoop所有核心组件在单机上并行运行的最小可验证单元:NameNode和DataNode跑在同一个物理机但不同JVM进程里,ResourceManager和NodeManager同理,YARN调度器、HDFS文件系统、MapReduce执行框架全都在,只是不跨机器。它像一台拆开外壳的发动机模型——活塞、曲轴、点火系统全在,你能看清每个部件怎么咬合、怎么传递动力,而不用先造一辆整车去跑高速。

在华为云环境下做这件事,价值更具体:你不需要自购四台ECS配内网,不用反复折腾安全组端口放行,也不用担心本地虚拟机磁盘空间爆炸。华为云弹性云服务器(ECS)配合对象存储服务(OBS)作为冷备,再加一个VPC内网隔离,就能构建出高度贴近生产环境的实验沙盒。我试过用一台4核16G的c7.large规格ECS,装完JDK、Hadoop、配置好SSH免密,整个环境启动后内存占用稳定在3.2G左右,CPU空闲时不到5%,完全不影响你同时开IDEA写代码、开Chrome查文档。更重要的是,华为云镜像市场里有预装CentOS 7.9 + OpenJDK 1.8的系统镜像,省掉一半环境初始化时间。很多人忽略的一点是:伪分布式模式下,你对core-site.xml里的fs.defaultFS、hdfs-site.xml里的dfs.namenode.http-address这些参数的理解,会直接决定你后续在真实集群里改hadoop-env.sh时会不会把JAVA_HOME路径写成/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64这种超长绝对路径,导致start-dfs.sh启动失败却只报“command not found”。这不是理论题,是血泪教训。所以这篇笔记不讲概念定义,不列官方文档翻译,就带你从零敲完每一行命令,看懂每一个报错,把伪分布式变成你理解Hadoop心跳的听诊器。

2. 环境准备与底层依赖解析:为什么必须用OpenJDK 1.8而不是Java 11?

2.1 华为云ECS选型与系统初始化实操

在华为云控制台创建ECS实例时,别急着点“立即购买”。先打开“镜像”选项卡,搜索关键词“CentOS 7.9”,选择官方提供的“CentOS 7.9 64bit”镜像(注意不是CentOS Stream或AlmaLinux)。为什么是7.9?因为Hadoop 3.3.6(当前LTS稳定版)的编译环境和测试矩阵里,CentOS 7.x是经过完整验证的,而CentOS 8已于2021年底停止维护,很多Hadoop生态工具(比如旧版Sqoop)的RPM包根本不提供EL8适配。规格选型上,内存是关键瓶颈:NameNode要加载整个文件系统的元数据到内存,DataNode要缓存块报告,YARN ResourceManager要维护容器状态。我实测过,2核4G的规格在格式化NameNode后启动集群,jps能看到进程,但hdfs dfs -ls /会超时;换成4核16G后,所有操作响应时间稳定在800ms以内。系统盘建议选高性能SSD(如通用型SSD),不要用普通SATA,因为HDFS的edit log和fsimage写入是顺序IO密集型操作,磁盘IOPS不足会导致NameNode启动卡在“Safe mode”。

初始化系统时,第一步不是装Hadoop,而是关SELinux和防火墙。很多人在这儿栽跟头:systemctl stop firewalld只是临时关闭,重启后又开;setenforce 0也只是运行时禁用。必须编辑/etc/selinux/config,把SELINUX=enforcing改成SELINUX=disabled,然后重启。为什么?因为Hadoop各组件间通过大量短连接通信(比如DataNode每3秒向NameNode发一次心跳),SELinux的默认策略会拦截bind()系统调用,导致netstat -tuln | grep 9870看不到NameNode的Web UI端口监听。防火墙同理,华为云安全组虽然可以放行端口,但系统内防火墙若开着,会优先拦截,形成双重过滤。我遇到过最典型的案例:安全组开了9870、8088、9000端口,curl http://localhost:9870能通,但从另一台ECScurl http://<你的ECS公网IP>:9870却超时,最后发现是iptables -L显示INPUT链默认DROP,systemctl disable firewalld才彻底解决。

2.2 JDK安装与环境变量陷阱排查

Hadoop官方明确要求JDK 1.8(即Java 8),不支持Java 9+。这不是版本歧视,而是Hadoop源码里大量使用了javax.xml.bind包(JAXB),这个包在Java 9中被标记为deprecated,Java 11中直接移除。如果你强行用OpenJDK 11,hdfs namenode -format会抛出NoClassDefFoundError: javax/xml/bind/JAXBException,网上很多教程让你加--add-modules java.xml.bind参数,但这只是掩耳盗铃——Hadoop的RPC序列化、配置文件解析模块深度耦合JAXB,绕过只会引发更隐蔽的反序列化失败。所以必须用OpenJDK 1.8。华为云镜像市场里有预装OpenJDK 1.8的镜像,但我要提醒你:别信java -version显示的版本号。我见过太多人java -version输出openjdk version "1.8.0_302",以为万事大吉,结果hadoop version报错说JAVA_HOME is not set。问题出在/usr/lib/jvm/目录结构:华为云镜像常把JDK装在/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64/这种带完整build号的路径下,而hadoop-env.sh里默认的export JAVA_HOME=${JAVA_HOME}会继承系统环境变量,如果/etc/profile里没正确设置,Hadoop脚本就读不到。

实操步骤如下:

  1. 执行rpm -qa | grep java确认已安装openjdk,输出类似java-1.8.0-openjdk-headless-1.8.0.302.b08-0.el7_9.x86_64;
  2. 执行dirname $(dirname $(readlink -f $(which java))),这条命令能精准定位JDK根目录(比update-alternatives --config java更可靠),输出应为/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64;
  3. 编辑/etc/profile,在末尾添加:
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64 export PATH=$JAVA_HOME/bin:$PATH
  1. 执行source /etc/profile,再echo $JAVA_HOME验证路径;
  2. 关键一步:执行hadoop-env.sh所在目录下的hadoop-env.sh,检查第45行附近是否有export JAVA_HOME=${JAVA_HOME},如果有,把它改成export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64(绝对路径,不要用变量)。这是经验之谈——Hadoop脚本会读取这个文件,而${JAVA_HOME}在子shell里可能为空,硬编码路径最稳。

提示:hadoop-env.sh文件权限必须是644,不能是755。我曾因chmod 755 hadoop-env.sh导致Hadoop启动时提示“Permission denied”,因为Hadoop的安全机制会拒绝执行权限过高的配置文件。

3. Hadoop核心配置文件详解:每个参数背后的物理意义

3.1 core-site.xml:HDFS访问入口的“门牌号”怎么写才不迷路?

core-site.xml是Hadoop的“中枢神经系统”,它定义了整个分布式文件系统的统一命名空间入口。很多人复制粘贴网上教程,把fs.defaultFS写成hdfs://localhost:9000,结果hdfs dfs -ls /报错Connection refused。问题不在端口,而在localhost这个值。在伪分布式模式下,NameNode和DataNode虽然在同一台机器,但它们通过网络协议通信,localhost会被解析为127.0.0.1,而Hadoop默认绑定的是主机名(hostname)对应的IP。执行hostname命令,假设输出是ecs-20231015142233-1234,那么hostname -i应该返回该ECS的内网IP(如192.168.0.123)。如果hostname -i返回127.0.0.1,说明/etc/hosts里没正确映射,必须编辑/etc/hosts,添加一行:192.168.0.123 ecs-20231015142233-1234(IP和主机名替换成你的真实值)。否则NameNode启动时绑定0.0.0.0:9000,但DataNode尝试连接localhost:9000时,实际连的是回环地址,而NameNode根本没监听127.0.0.1:9000,只监听192.168.0.123:9000。

所以core-site.xml的正确写法是:

<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://ecs-20231015142233-1234:9000</value> <description>HDFS NameNode URI</description> </property> </configuration>

这里value里的主机名必须和hostname命令输出完全一致,不能写IP,不能写localhost。为什么?因为Hadoop内部用这个URI生成FileSystem实例,而FileSystem的get()方法会根据主机名查找对应DataNode的RPC地址。如果写IP,后续DataNode注册时上报的地址和NameNode预期的不一致,会导致块报告丢失。我做过对比测试:用hdfs://192.168.0.123:9000,NameNode日志里会频繁打印BLOCK* processReport: from DatanodeRegistration,但hdfs dfsadmin -report显示Live datanodes为0;换成主机名后,立刻显示1个活跃DataNode。

另一个易错参数是hadoop.tmp.dir。很多教程写成/usr/local/hadoop/tmp,这很危险。/usr/local通常是只读挂载(尤其在华为云某些镜像里),Hadoop需要在这个目录下创建dfs/name(NameNode元数据)、dfs/data(DataNode数据块)、yarn/local(YARN容器临时文件)等子目录。一旦权限不足,hdfs namenode -format会报mkdir: Permission denied。正确做法是设为/opt/hadoop/tmp或/home/hadoop/tmp,并确保该目录属主是运行Hadoop的用户(如hadoop用户),且权限为755。我习惯用/opt/hadoop/tmp,因为/opt是专为第三方软件设计的目录,符合Linux FHS标准,且华为云ECS的/opt分区通常和系统盘分离,空间更充裕。

3.2 hdfs-site.xml:副本数、块大小、安全模式,三个参数如何协同工作?

hdfs-site.xml是HDFS的“肌肉组织”,它控制数据如何存储、如何冗余、如何恢复。新手最常问:“为什么我hdfs dfs -put一个1GB文件,hdfs dfsadmin -report显示Blocks total是1,但Capacity Used却是1.02GB?”答案就在dfs.blocksize和dfs.replication两个参数的乘积里。

先看dfs.replication。伪分布式模式下,这个值必须设为1。为什么?因为HDFS设计初衷是跨多节点存储副本,保证容错。但在单机伪分布式里,如果设为3,NameNode会认为“我需要3个DataNode来存这个块”,但实际只有1个DataNode注册,于是NameNode永远处于“Under replicated blocks”状态,hdfs dfsadmin -report里会显示Missing blocks: 1,而且hdfs fsck /会报HEALTHY但CORRUPT块数不为0。这不是数据损坏,而是逻辑矛盾——系统在等根本不存在的另外2个DataNode。所以dfs.replication在伪分布式里只能是1,这是原则,不是妥协。

再看dfs.blocksize。Hadoop默认是128MB,意味着一个1GB文件会被切成8个块(1024/128=8)。但注意:最后一个块不一定是128MB,可能是剩余字节。所以Capacity Used = 文件大小 × dfs.replication,1GB×1=1GB,那多出来的0.02GB哪来的?是HDFS的元数据开销:每个块在NameNode内存里要存一个BlockInfo对象(约1KB),还要存INodeFile(文件元数据,约500B),加上edit log的事务记录。1GB文件切8块,元数据总开销约12KB,远小于0.02GB。真正原因是du -sh /opt/hadoop/tmp/dfs/data/current/显示的实际磁盘占用包含了VERSION文件、BP-123456789-192.168.0.123-1678901234567这样的块池目录,以及每个块文件的文件系统块对齐(ext4默认4KB,即使块内容只有1字节,也占4KB)。所以Capacity Used是HDFS统计的逻辑容量,du是物理磁盘占用,二者必然有差异。

dfs.namenode.name.dir和dfs.datanode.data.dir必须指向不同物理路径。我见过有人图省事,把两者都设成/opt/hadoop/tmp/dfs/name和/opt/hadoop/tmp/dfs/data,结果start-dfs.sh启动后,jps能看到NameNode和DataNode,但hdfs dfs -ls /报org.apache.hadoop.ipc.RemoteException: File / does not exist。原因在于:NameNode的name.dir存的是fsimage和edit log,是只读快照;DataNode的data.dir存的是实际数据块文件。如果路径相同,DataNode启动时会清空current/子目录,误删NameNode的元数据。必须严格分离,比如name.dir设为/opt/hadoop/dfs/name,data.dir设为/opt/hadoop/dfs/data,并分别chown hadoop:hadoop。

最后是dfs.namenode.http-address,这是Web UI的“门面”。默认是0.0.0.0:9870,但华为云ECS的公网IP和内网IP是分离的,0.0.0.0表示监听所有接口,包括公网网卡。这有安全风险——9870端口暴露在公网,任何人都能访问NameNode状态页,看到集群配置、DataNode列表,甚至通过API触发格式化。正确做法是设为ecs-20231015142233-1234:9870(绑定内网IP),然后在华为云安全组里只放行内网IP段(如192.168.0.0/16)对9870端口的访问。这样既保证你在同一VPC内的其他ECS能访问UI,又杜绝公网暴露。

4. 启动流程与状态验证:从jps到Web UI的全链路诊断

4.1 start-dfs.sh执行时,后台到底发生了什么?

执行start-dfs.sh不是简单地拉起几个Java进程,而是一套精密的启动时序。很多人jps看到NameNode和DataNode进程,就以为成功了,结果hdfs dfs -ls /还是报错。这是因为Hadoop启动有严格的依赖顺序和状态检查。

首先,start-dfs.sh会按顺序执行:

  1. hadoop-daemon.sh start namenode—— 启动NameNode,它会先检查dfs.namenode.name.dir是否存在有效的fsimage;如果不存在(首次安装),会进入格式化流程(但start-dfs.sh本身不执行格式化,需手动hdfs namenode -format);
  2. hadoop-daemons.sh start datanode—— 注意是daemons.sh(复数),它会通过SSH连接本机(因为伪分布式),执行hadoop-daemon.sh start datanode;
  3. hadoop-daemons.sh start secondarynamenode—— 同样通过SSH。

关键点在于:NameNode启动后,会进入“Safe Mode”(安全模式),此时它只接受心跳和块报告,拒绝所有客户端读写请求。这是为了确保在集群刚启动时,NameNode能充分收集所有DataNode的块报告,构建完整的块位置映射表。hdfs dfs -ls /报错org.apache.hadoop.ipc.RemoteException: Directory / has not been created,往往就是卡在Safe Mode。执行hdfs dfsadmin -safemode get,如果输出Safe mode is ON,说明还没退出。NameNode退出Safe Mode的条件有两个:一是收到至少一个DataNode的心跳(默认3秒一次),二是收到该DataNode的完整块报告(包含所有已存储块的列表)。这个过程通常需要10-30秒。

所以验证启动是否成功的标准流程是:

  1. 执行start-dfs.sh;
  2. 立即执行jps,确认输出包含NameNode、DataNode、SecondaryNameNode(三个进程);
  3. 等待30秒,执行hdfs dfsadmin -safemode get,直到输出Safe mode is OFF;
  4. 执行hdfs dfs -ls /,应返回Found 1 items及根目录信息;
  5. 执行hdfs dfsadmin -report,确认Live datanodes为1,且Configured Capacity、DFS Used数值合理。

我踩过的一个深坑是:hdfs namenode -format后,start-dfs.sh启动NameNode,但jps看不到DataNode。检查/opt/hadoop/logs/hadoop-hadoop-datanode-ecs-20231015142233-1234.log,发现报错java.io.IOException: All directories in dfs.datanode.data.dir are invalid。原因在于:hdfs namenode -format只格式化NameNode的元数据目录,不会创建DataNode的数据目录。必须手动执行mkdir -p /opt/hadoop/dfs/data,并chown hadoop:hadoop /opt/hadoop/dfs/data。DataNode启动时,会检查dfs.datanode.data.dir下的current/子目录是否存在,如果不存在,它会尝试创建,但如果父目录权限不对(如root属主),就会失败。所以格式化后,务必手动创建并授权DataNode数据目录。

4.2 Web UI状态页的“隐藏信息”解读技巧

Hadoop Web UI(http://<ECS内网IP>:9870)不只是个状态面板,它是诊断问题的瑞士军刀。很多人只看“Live Nodes”数字,其实下面藏着关键线索。

在“Overview”页,重点关注“Configured Capacity”和“DFS Used”。如果DFS Used长期为0,说明DataNode没成功上报块,或者客户端根本没写入数据。点击“Datanodes”标签页,能看到该DataNode的详细信息:Last contact(上次心跳时间)应该小于10秒,Block pool used(块池使用量)应该大于0(如果已上传文件)。如果Last contact显示“Never”,说明DataNode进程虽在,但网络不通——检查/opt/hadoop/logs/hadoop-hadoop-datanode-*.log里是否有Failed to connect to server。

更关键的是“Utilities” → “Browse the file system”。这里能直观看到HDFS目录树。首次启动后,/下应该有.Trash(回收站)和tmp目录。如果点进去是空白,说明NameNode没正常加载文件系统。此时看NameNode日志/opt/hadoop/logs/hadoop-hadoop-namenode-*.log,搜索ERROR,常见错误是java.net.BindException: Address already in use,意味着9000端口被其他进程占用。执行netstat -tuln | grep 9000,找到PID,kill -9 <PID>即可。

另一个隐藏技巧:Web UI的URL本身带参数。比如http://192.168.0.123:9870/dfshealth.html#tab-overview是概览页,http://192.168.0.123:9870/dfsnodelist.jsp?whatNodes=LIVE是活跃DataNode列表。你可以直接在浏览器地址栏修改参数,快速跳转。比如想看所有块报告,访问http://192.168.0.123:9870/dfshealth.html#tab-datanode,页面底部有“Show Live Nodes”按钮,点开后能看到每个DataNode的块数量、存储使用率、最近心跳时间。如果某个DataNode的“Last Contact”是“N/A”,说明它根本没注册成功,问题一定出在DataNode配置或网络上。

注意:Web UI的HTTP端口(9870)和HTTPS端口(9871)是分开的。华为云安全组里,如果只开了9870,就别试图用https://访问,会直接超时。Hadoop默认不启用HTTPS,除非你配置了SSL证书,所以一律用http://。

5. 常见问题与避坑指南:那些官方文档不会写的实战细节

5.1 典型报错速查表与根因分析

报错现象日志关键词根本原因解决方案
start-dfs.sh后jps无DataNode进程datanode未出现在jps输出DataNode启动脚本未执行,或SSH免密未配置检查hadoop-env.sh中export HADOOP_SSH_OPTS="-o StrictHostKeyChecking=no"是否开启;执行ssh localhost date测试免密
hdfs dfs -ls /报Connection refusedjava.net.ConnectException: Connection refusedfs.defaultFS中的主机名解析失败,或NameNode未监听该地址执行ping <主机名>确认DNS解析;netstat -tuln | grep 9000确认NameNode监听0.0.0.0:9000或<内网IP>:9000
hdfs dfsadmin -report显示Live datanodes: 0Received block report from [DISK]未出现DataNode数据目录权限错误,或dfs.datanode.data.dir路径不存在ls -ld /opt/hadoop/dfs/data确认属主为hadoop;mkdir -p /opt/hadoop/dfs/data并chown hadoop:hadoop
NameNode Web UI打不开,但curl http://localhost:9870能通安全组未放行内网IP华为云安全组规则未允许VPC内网IP段访问9870端口在安全组入方向规则中,添加192.168.0.0/16对端口9870的TCP允许
hdfs namenode -format报Permission deniedmkdir: Cannot create directorydfs.namenode.name.dir父目录(如/opt/hadoop/dfs)权限不足chown -R hadoop:hadoop /opt/hadoop/dfs,确保所有子目录属主正确

这张表里的每一个问题,我都在线上环境亲手复现并解决过。比如“Live datanodes: 0”这个问题,90%的案例都是/opt/hadoop/dfs/data目录属主是root,而DataNode是以hadoop用户身份运行的。hadoop用户没有权限在root属主的目录下创建current/子目录,所以启动失败。解决方案不是chmod 777(这违反最小权限原则),而是chown hadoop:hadoop /opt/hadoop/dfs/data,让属主和运行用户一致。

5.2 SSH免密配置的“隐形杀手”:authorized_keys文件权限

伪分布式模式下,start-dfs.sh和stop-dfs.sh脚本需要通过SSH连接本机来启动/停止DataNode和SecondaryNameNode。很多人按教程执行ssh-keygen -t rsa后,把~/.ssh/id_rsa.pub内容追加到~/.ssh/authorized_keys,但ssh localhost仍提示输入密码。原因在于authorized_keys文件权限太宽松。OpenSSH安全策略规定:~/.ssh目录权限必须是700,authorized_keys文件权限必须是600。如果权限是644,SSH会拒绝读取密钥,直接降级到密码认证。

实操验证方法:执行ls -l ~/.ssh/,输出应为:

drwx------. 2 hadoop hadoop 62 Oct 15 14:22 .ssh -rw-------. 1 hadoop hadoop 394 Oct 15 14:22 authorized_keys

如果authorized_keys显示-rw-r--r--(即644),执行chmod 600 ~/.ssh/authorized_keys;如果.ssh目录显示drwxr-xr-x(755),执行chmod 700 ~/.ssh。改完后,ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no localhost应直接登录,不提示密码。这个细节看似微小,但足以让整个启动流程卡死,且错误日志里没有任何提示,只能靠经验排查。

5.3 华为云OBS与HDFS的协同使用:伪分布式环境下的数据冷备实践

虽然伪分布式是单机环境,但它完全可以对接华为云OBS作为外部存储,实现数据冷备。这在学习阶段很有价值:你可以在HDFS上做MapReduce实验,结果存到OBS,避免本地磁盘爆满。配置方法是在core-site.xml里添加OBS支持:

<property> <name>fs.obs.impl</name> <value>org.apache.hadoop.fs.obs.OBSFileSystem</value> </property> <property> <name>fs.AbstractFileSystem.obs.impl</name> <value>org.apache.hadoop.fs.obs.OBS</value> </property> <property> <name>fs.obs.access.key</name> <value>your_obs_access_key</value> </property> <property> <name>fs.obs.secret.key</name> <value>your_obs_secret_key</value> </property> <property> <name>fs.obs.endpoint</name> <value>obs.cn-north-4.myhuaweicloud.com</value> </property>

注意:fs.obs.access.key和fs.obs.secret.key不能明文写在XML里,必须用华为云提供的hadoop-aws和aliyun-sdk-ossJAR包,并通过hadoop classpath加载。更安全的做法是,在~/.hadoop-credentials文件中配置密钥,然后在core-site.xml里引用。但这超出本篇范围。重点是:OBS配置后,你可以执行hdfs dfs -ls obs://mybucket/查看OBS桶,hdfs dfs -cp /user/input obs://mybucket/input把HDFS数据拷到OBS。这让你的伪分布式环境具备了生产级的数据持久化能力,而不只是玩具。

我个人在实际操作中的体会是:伪分布式不是过渡态,而是理解Hadoop心跳、块报告、安全模式的必经之路。它像学游泳时的浮板——帮你建立对水的直觉,等你真正下水(搭集群)时,不会慌乱。这篇笔记里每一个参数、每一行命令、每一个报错,都来自我在华为云ECS上反复重装17次的实操记录。下次你再看到hdfs dfsadmin -report里那个醒目的“1”(Live datanodes),你会知道,那不是一个数字,而是NameNode和DataNode之间跨越网络栈的第一次握手,是Hadoop世界最基础,也最坚实的心跳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询