1.前言
本文档适合3节点的Hadoop 高可用(HA:High Available)测试集群集群的搭建。
在上一篇文章中《Hadoop3.x入门-搭建3节点分布式集群》只是一个简单的测试的分布式集群,并不是高可用的,也就是说当namenode或者resourcemanager节点挂掉,hadoop的功能就无法使用了,所以无法应用到生产环境中。
本文在上一篇的基础上修改一些配置,将Hadoop集群改造为高可用集群。如果用上一篇文章搭建的集群,首先关闭集群所有进程,删除$HADOOP_HOME/data目录,以防出一些问题。
2.搭建前提条件
jdk1.8,节点间免密(包括本地免密),关闭防火墙,关闭selinux,设置主机域名并配置到hosts文件中,修改Linux部署用户的最大进程数,修改Linux部署用户的打开最大文件数。
*以上步骤自行配置
3.集群规划
实验环境在Centos7中进行,hadoop版本3.3.2,zookeeper版本3.5.9。
HDFS高可用需要服务: Zookeeper/NameNode/DataNode/JournalNode/ZKFC
Yarn高可用需要:Zookeeper/ResourceManager/NodeManager
主机名 | hd1.dev.local | hd2.dev.local | hd3.dev.local |
对应节点上的服务进程,集群部署好通过JPS即可查到对应进程名称 | QuorumPeerMain | QuorumPeerMain | QuorumPeerMain |
JournalNode | JournalNode | JournalNode | |
NameNode | NameNode | NameNode | |
DataNode | DataNode | DataNode | |
DFSZKFailoverController | DFSZKFailoverController | DFSZKFailoverController | |
ResourceManager | ResourceManager | ResourceManager | |
NodeManager | NodeManager | NodeManager | |
JobHistoryServer |
4.HDFS高可用
4.1修改core-site.xml
<configuration>
<!-- 指定NameNode的地址-单节点 -->
<!-- <property>
<name>fs.defaultFS</name>
<value>hdfs://hd1.dev.local:8020</value>
</property> -->
<!-- Namenode高可用配置-自定义集群名称,且不用指定端口号 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://hacluster</value>
</property>
<!-- 指定hadoop数据的存储目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/module/hadoop-3.3.2/data</value>
</property>
<!-- 配置HDFS网页登录使用的静态用户为dev -->
<property>
<name>hadoop.http.staticuser.user</name>
<value>dev</value>
</property>
<!-- 配置ZKFC进程连接zookeeper的地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hd1.dev.local:2181,hd2.dev.local:2181,hd3.dev.local:2181</value>
</property>
</configuration>
4.2修改hdfs-site.xml
<configuration>
<!-- Namenode web端http访问地址-单节点配置-->
<!-- <property>
<name>dfs.namenode.http-address</name>
<value>hd1.dev.local:9870</value>
</property> -->
<!-- SecondaryNameNode web端http访问地址-单节点集群配置-->
<!-- <property>
<name>dfs.namenode.secondary.http-address</name>
<value>hd3.dev.local:9868</value>
</property> -->
<!-- Namenode 数据存储目录-->
<property>
<name>dfs.namenode.name.dir</name>
<value>file://${hadoop.tmp.dir}/name</value>
</property>
<!-- Datanode 数据存储目录-->
<property>
<name>dfs.namenode.data.dir</name>
<value>file://${hadoop.tmp.dir}/data</value>
</property>
<!-- journalnode 数据存储目录-->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>${hadoop.tmp.dir}/jn</value>
</property>
<!-- 指定集群逻辑名字为hacluster 与 core-site中保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>hacluster</value>
</property>
<!-- 指定逻辑namenode的节点,自定义名称为nn1,2,3 -->
<property>
<name>dfs.ha.namenodes.hacluster</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- 定义nn1的rpc通信地址 -->
<property>
<name>dfs.namenode.rpc-address.hacluster.nn1</name>
<value>hd1.dev.local:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.hacluster.nn2</name>
<value>hd2.dev.local:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.hacluster.nn3</name>
<value>hd3.dev.local:8020</value>
</property>
<!-- 定义nn1的web页面的http地址 -->
<property>
<name>dfs.namenode.http-address.hacluster.nn1</name>
<value>hd1.dev.local:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.hacluster.nn2</name>
<value>hd2.dev.local:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.hacluster.nn3</name>
<value>hd3.dev.local:9870</value>
</property>
<!-- 定义namenode元数据在journalnode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hd1.dev.local:8485;hd2.dev.local:8485;hd3.dev.local:8485/hacluster</value>
</property>
<!-- 访问代理类:访问hacluster时,client用于确定哪个NameNode为Active,将请求转发过去 -->
<property>
<name>dfs.client.failover.proxy.provider.hacluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<!-- 配置隔离机制时需要的ssh密钥登录 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/dev/.ssh/id_rsa</value>
</property>
<!-- 启动namenode故障自动转移 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
</configuration>
4.3同步配置文件
将hdfs-site.xml和core-site.xml复制到其他俩个节点上
4.4启动zookeeper集群
zookeeper集群自行搭建
执行启动zk命令:
bin/zkServer.sh start
检查启动情况: jps ,每个节点包含QuorumPeerMain进程代表zk集群启动成功或者每个节点执行:bin/zkServer.sh status,查看是否有leader节点。
4.5每个namenode节点上启动journalnode进程
hdfs --daemon start journalnode
4.6在第一台namenode节点上格式化namenode
hdfs namenode -format
启动这台节点的namenode
hdfs --daemon start namenode
其他Namenode节点上首次要手动同步一次数据,在另外俩个节点执行:
hdfs namenode -bootstrapStandby
同步完成后启动namenode
hdfs --daemon start namenode
4.7初始化ZKFC
ZKFC用于监控active namenode节点是否挂掉,通知其它节点上的ZKFC强行杀死自己ZKFC节点上的namenode(防止其假死状态产生集群namenode脑裂的发生),然后选举出其他namenode为active节点
集群首次搭建需要在zookeeper中初始化namenode信息,在namenode1节点执行命令:
hdfs zkfc -formatZK
4.8启动HDFS相关进程
在namenode1节点上,启动HDFS整个集群(包括其他节点)的其他进程(Datanode/DFSZKFailoverController),执行命令:
sbin/start-dfs.sh
4.9查看active节点
进入zookeeper中,./bin/zkCli.sh ,执行:
get -s /hadoop-ha/hacluster/ActiveStandbyElectorLock
查看到的节点即为active节点,进入对应节点页面(9870)查看状态为active
或者执行:
hdfs haadmin -getAllServiceState
即显示Active节点是哪个
4.10验证高可用
kill -9 active namenode进程,查看页面状态,可发现另外某个namenode自动切换成active状态。
记住kill掉的,实验结束后再启动起来。
4.11验证集群是否可用
hdfs dfs -mkdir hdfs://hacluster/wordcount
hdfs dfs -put wordcount.txt hdfs://hacluster:/wordcount
hdfs dfs -ls hdfs://hacluster/wordcount
5.Yarn高可用
5.1修改yarn-site.xml
<configuration>
<!-- Site specific YARN configuration properties -->
<!-- 指定MR走shuffle -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- 指定ResourceManager的地址 单节点配置-->
<!-- <property>
<name>yarn.resourcemanager.hostname</name>
<value>hd2.dev.local</value>
</property> -->
<!-- 环境变量的继承 -->
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
<!-- 开启resourcemanager HA-->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 自定义一个resourcemanager的逻辑集群id-->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yarn-cluster</value>
</property>
<!-- 指定resourcemanager集群的逻辑节点名称列表-->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2,rm3</value>
</property>
<!-- rm1的节点信息-->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hd1.dev.local</value>
</property>
<!-- yarn web页面地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hd1.dev.local:8088</value>
</property>
<!-- rm1 对客户端暴露的地址,客户端通过该地址向RM提交任务等 -->
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hd1.dev.local:8032</value>
</property>
<!-- rm1 与 applicationMaster的通信地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hd1.dev.local:8030</value>
</property>
<!-- rm1 与 nm的通信地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hd1.dev.local:8031</value>
</property>
<!-- rm2的节点信息-->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hd2.dev.local</value>
</property>
<!-- yarn web页面地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>hd2.dev.local:8088</value>
</property>
<!-- rm2 对客户端暴露的地址,客户端通过该地址向RM提交任务等 -->
<property>
<name>yarn.resourcemanager.address.rm2</name>
<value>hd2.dev.local:8032</value>
</property>
<!-- rm2 与 applicationMaster的通信地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>hd2.dev.local:8030</value>
</property>
<!-- rm2 与 nm的通信地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm2</name>
<value>hd2.dev.local:8031</value>
</property>
<!-- rm3的节点信息-->
<property>
<name>yarn.resourcemanager.hostname.rm3</name>
<value>hd3.dev.local</value>
</property>
<!-- yarn web页面地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm3</name>
<value>hd3.dev.local:8088</value>
</property>
<property>
<name>yarn.resourcemanager.address.rm3</name>
<value>hd3.dev.local:8032</value>
</property>
<!-- rm3 与 applicationMaster的通信地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm3</name>
<value>hd3.dev.local:8030</value>
</property>
<!-- rm3 与 nm的通信地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm3</name>
<value>hd3.dev.local:8031</value>
</property>
<!-- 配置zookeeper信息 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hd1.dev.local:2181,hd2.dev.local:2181,hd3.dev.local:2181</value>
</property>
<!-- 启动自动恢复 -->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<!-- 配置将recourcemanager的状态信息存储在zookeeper中 -->
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
</configuration>
5.2启动yarn集群
在namenode1节点上进入sbin目录:
./start-yarn.sh
5.3启动JobHistroy
在第一台节点上启动JobHistroy日志管理进程:
mapred --daemon start historyserver
5.4查看进程状态
每个节点执行jps命令,此时进程结果为:
主机名 | hd1.dev.local | hd2.dev.local | hd3.dev.local |
进程名称 | QuorumPeerMain | QuorumPeerMain | QuorumPeerMain |
JournalNode | JournalNode | JournalNode | |
NameNode | NameNode | NameNode | |
DataNode | DataNode | DataNode | |
DFSZKFailoverController | DFSZKFailoverController | DFSZKFailoverController | |
ResourceManager | ResourceManager | ResourceManager | |
NodeManager | NodeManager | NodeManager | |
JobHistoryServer |
如果进程数据不对,则需要进入$HADOOP_HOME/logs下找对应没启动起来的进程的日志,查明启动失败原因。
5.4验证Yarn高可用
访问任意resourcemanager节点的8088都会跳转到固定的一个resourcemanager节点上,说明高可用配置成功。
Kill掉固定节点上的resourcemanager进程,继续访问8088端口,发现地址已转变到其它resourcemanager节点上,说明高可用验证成功。
也可通过命令查看所有节点状态:
yarn rmadmin -getAllServiceState
5.5查看Yarn页面
此时访问任意resourcemanager节点的8088端口都会自动跳转到active节点的yarn地址
5.6执行wordcount
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.2.jar wordcount /wordcount /tmp/wdoutput1
有输出结果即可。
至此Hadoop 3节点高可用测试集群搭建完毕。