1. 新建目录与解压 Hadoop
首先,在所有三台节点上创建用于安装 Hadoop 的新目录,并将 Hadoop 压缩包解压到该目录。
bash
# 三台节点执行
mkdir /opt/module/hadoop-HA
tar -zxvf hadoop-3.1.4.tar.gz -C /opt/module/hadoop-HA
2. 配置环境变量
修改所有节点的 /etc/profile
文件,配置新的 HADOOP_HOME
路径,并使其生效。
bash
# 在所有节点上编辑 /etc/profile
vim /etc/profile
# 找到之前的 HADOOP_HOME 并注释掉
# export HADOOP_HOME=/opt/module/hadoop-3.1.4
# 添加新的 HADOOP_HOME 路径
export HADOOP_HOME=/opt/module/hadoop-HA/hadoop-3.1.4
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# 使环境变量生效
source /etc/profile
# 验证是否成功
hadoop version
3. 修改 Hadoop 配置文件
在 master
节点上,进入 /opt/module/hadoop-HA/hadoop-3.1.4/etc/hadoop/
目录,并修改以下配置文件。
hadoop-env.sh
指定 Hadoop 使用的 JDK 和运行各个守护进程的用户。
bash
vim hadoop-env.sh
bash
export JAVA_HOME=/opt/module/jdk1.8.0_261
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_JOURNALNODE_USER=root
export HDFS_ZKFC_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
core-site.xml
配置 HDFS 的通信地址、临时数据存储目录、代理用户和 ZooKeeper 集群地址。
bash
vim core-site.xml
xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluter</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/module/hadoop-HA/hadoop-3.1.4/data/hadoop</value>
</property>
<property>
<name>hadoop.http.staticuser.user</name>
<value>root</value>
</property>
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.users</name>
<value>*</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>master:2181,slave1:2181,slave2:2181</value>
</property>
</configuration>
hdfs-site.xml
配置 HDFS 副本数、NameNode 和 DataNode 的数据目录、HA 相关设置,以及自动故障转移和 Fencing 机制。
bash
vim hdfs-site.xml
xml
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/module/hadoop-HA/hadoop-3.1.4/data/hadoop/namenode</value>
</property>
<property>
<name>dfs.datanode.dir</name>
<value>/opt/module/hadoop-HA/hadoop-3.1.4/data/hadoop/datanode</value>
</property>
<property>
<name>dfs.nameservices</name>
<value>mycluter</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluter</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluter.nn1</name>
<value>master:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluter.nn1</name>
<value>master:9870</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluter.nn2</name>
<value>slave1:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluter.nn2</name>
<value>slave1:9870</value>
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://master:8485;slave1:8485;slave2:8485/mycluter</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/opt/module/hadoop-HA/hadoop-3.1.4/data/hadoop/journaldata</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled.mycluter</name>
<value>true</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.mycluter</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.permissions.enable</name>
<value>false</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
</configuration>
mapred-site.xml
配置 MapReduce 运行在 YARN 上,并指定历史服务的地址。
xml
vim mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>master:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>master:19888</value>
</property>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
</configuration>
yarn-site.xml
配置 YARN 的高可用、ResourceManager 的标识符、ZooKeeper 地址、日志聚合和内存检查等。
xml
vim yarn-site.xml
<configuration>
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>jyarn</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>master</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>slave1</value>
</property>
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>master:2181,slave1:2181,slave2:2181</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</value>
</property>
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>master:8188</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>master:8130</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>slave1:8188</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>slave1:8130</value>
</property>
</configuration>
workers
指定集群中的所有 DataNode 主机名。
bash
vim workers
master
slave1
slave2
4. 远程分发配置
将配置好的 Hadoop 目录从 master
节点分发到 slave1
和 slave2
节点。
bash
# 在 master 节点执行
scp -r /opt/module/hadoop-HA/hadoop-3.1.4 slave1:/opt/module/hadoop-HA/
scp -r /opt/module/hadoop-HA/hadoop-3.1.4 slave2:/opt/module/hadoop-HA/
5. 启动集群
按照以下顺序启动集群服务:
-
启动 ZooKeeper 集群:在所有节点上启动 ZooKeeper,并检查其状态。
bash# 在所有节点上执行 zkServer.sh start zkServer.sh status
正确状态应为一台
leader
,其余为follower
。 -
启动 JournalNode:在所有节点上启动 JournalNode。
bash# 在所有节点上执行 hdfs --daemon.sh start journalnode
-
格式化 HDFS (仅首次) :在
master
(nn1) 上格式化 HDFS 文件系统。bashhdfs namenode -format
-
同步 NameNode :将
master
上的 NameNode 数据同步到slave1
。bash# 在 master 节点执行 scp -r /opt/module/hadoop-HA/hadoop-3.1.4/data/hadoop/namenode slave1:/opt/module/hadoop-HA/hadoop-3.1.4/data/hadoop
-
格式化 ZKFC :在
master
(nn1) 上格式化 ZKFC,以便 ZooKeeper 管理主备切换。bashhdfs zkfc -formatZK
-
启动 NameNode 和 ZKFC :在
master
和slave1
上分别启动 NameNode 和 ZKFC。bash# 在 master 和 slave1 上执行 hdfs --daemon.sh start namenode hdfs --daemon.sh start zkfc
注意 :如果你想启动所有服务,可以使用
start-dfs.sh
和start-yarn.sh
,但前提是所有配置和环境(例如 ssh 免密登录)都已正确设置。
成功运行图如下所示
注意我这配置yarn端口为8188而不是 8088
6. 故障转移测试
HDFS NameNode 故障转移
-
查看 NameNode 状态 :确认
nn1
和nn2
的状态。bashhdfs haadmin -getAllServiceState
-
手动主备切换 :将
nn1
切换为standby
,nn2
切换为active
。bashhdfs haadmin -failover nn1 nn2
-
模拟故障 :在
master
上杀死 NameNode 进程。bash# 可以通过 `jps` 查看pid # 在 master 节点执行 kill -9 (namenode pid)
-
验证自动切换 :再次查看 NameNode 状态,
nn2
应该自动切换为active
。bashhdfs haadmin -getServiceState nn1 # 显示 standby 或拒绝连接 hdfs haadmin -getServiceState nn2 # 显示 active
YARN ResourceManager 故障转移
-
查看 ResourceManager 状态:
bashyarn rmadmin -getServiceState rm1 yarn rmadmin -getServiceState rm2
-
模拟故障 :在
master
上杀死 ResourceManager 进程。bash# 在 master 节点执行 kill -9 (rm1)ResourceManager
-
验证自动切换 :再次查看 ResourceManager 状态,
rm2
应该自动切换为active
。bashyarn rmadmin -getServiceState rm1 # 拒绝连接 yarn rmadmin -getServiceState rm2 # active
7. 常见问题处理
如果遇到两个 NameNode 都处于 standby
状态,并且日志报错 Parent znode does not exist
,说明 ZooKeeper 中的 HA 状态没有正确初始化。
解决方法:
-
检查 ZooKeeper :确保 ZooKeeper 服务已启动,并检查
znode
是否存在。bashcd $ZOOKEEPER_HOME/bin ./zkCli.sh ls /
-
重新格式化 ZKFC :使用
-formatZK
标志重新初始化 ZKFC。bashhdfs zkfc -formatZK
-
重启服务:确认操作成功后,重新启动 Hadoop 集群。
bashstop-all.sh start-all.sh