一、HA原理
1. HDFS高可用
HDFS高可用解决了NN单点故障问题
(1) 正常工作时的原理架构图
a. ZKFC是一个进程,监控NN的健康状态 ,将所代理的NN信息写入到Zookeeper的节点中,该节点用作一把锁,只能允许一个ZKFC写入内容,成功写入内容的ZKFC所代理的NN会对外提供服务,状态变为Active,其他ZKFC所代理的NN都变成StandBy状态,不对外提供服务;
b. JN(Journal Node)是一个类似于Zookeeper的高可用集群,采用过半机制,JN中存储了NN的编辑日志文件,只有Active状态的NN有权限向JN中写入编辑日志,其他NN只能读取编辑日志文件,然后将该编辑日志文件在内存中和元数据合并,维护最新的元数据,以备Active状态的NN挂掉之后,自己补位;
(2) Active状态NN宕机后,故障切换的原理架构图
2. Yarn高可用
Yarn高可用解决了RM单点故障问题
原理类似于HDFS,Yarn中也有类似于ZKFC的进程,不同的是,Yarn将该进程直接集成到了内部,保持Yarn高可用的原理也是通过了Zookeeper的存储+通知机制,与HDFS这部分的处理完全一致。
二、HA环境搭建
关于集群如何搭建请参考:Hadoop概述、搭建完全分布式(非高可用)
搭建Zookpper集群请参考:Zookeeper基础
装完之后再进行如下步骤
下文中只会指出需要变动的地方,不变的安装内容不再赘述
1. HDFS HA搭建
四.1.(1)core-site.xml
<configuration>
<!-- 指定把多个NameNode的地址组装成一个集群,集群名自定义 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://hdfscluster</value>
</property>
<!-- 指定zkfc要连接的zkServer地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop101:2181,hadoop102:2181,hadoop103:2181</value>
</property>
<!-- 指定hadoop数据的存储目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/moudle/hadoop-3.1.3/data</value>
</property>
<!-- 配置HDFS网页登录使用的静态用户为soro-->
<property>
<name>hadoop.http.staticuser.user</name>
<value>soro</value>
</property>
<!-- 配置该soro(superUser)允许通过代理访问的主机节点 -->
<property>
<name>hadoop.proxyuser.soro.hosts</name>
<value>*</value>
</property>
<!-- 配置该soro(superUser)允许通过代理用户所属组 -->
<property>
<name>hadoop.proxyuser.soro.groups</name>
<value>*</value>
</property>
<!-- 配置该soro(superUser)允许通过代理的用户-->
<property>
<name>hadoop.proxyuser.soro.groups</name>
<value>*</value>
</property>
</configuration>
四.1.(2)hdfs-site.xml
<configuration>
<!-- NameNode数据存储目录 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>file://${hadoop.tmp.dir}/name</value>
</property>
<!-- DataNode数据存储目录 -->
<property>
<name>dfs.datanode.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>
<!-- 完全分布式集群名称 -->
<property>
<name>dfs.nameservices</name>
<value>hdfscluster</value>
</property>
<!-- 集群中NameNode节点都有哪些 -->
<property>
<name>dfs.ha.namenodes.hdfscluster</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- NameNode的RPC通信地址,端口号也可以为9820、9000 -->
<property>
<name>dfs.namenode.rpc-address.hdfscluster.nn1</name>
<value>hadoop101:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.hdfscluster.nn2</name>
<value>hadoop102:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.hdfscluster.nn3</name>
<value>hadoop103:8020</value>
</property>
<!-- NameNode的http通信地址 -->
<property>
<name>dfs.namenode.http-address.hdfscluster.nn1</name>
<value>hadoop101:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.hdfscluster.nn2</name>
<value>hadoop102:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.hdfscluster.nn3</name>
<value>hadoop103:9870</value>
</property>
<!-- 指定NameNode元数据在JournalNode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop101:8485;hadoop102:8485;hadoop103:8485/hdfscluster</value>
</property>
<!-- 访问代理类:client用于确定哪个NameNode为Active -->
<property>
<name>dfs.client.failover.proxy.provider.hdfscluster</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/soro/.ssh/id_rsa</value>
</property>
<!-- 启用nn故障自动转移 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
</configuration>
2. Yarn HA搭建
四.1.(3)yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- 启用resourcemanager ha -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 声明resourcemanagers的集群名 -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yarncluster</value>
</property>
<!--指定resourcemanagers有哪些-->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- rm1的配置 -->
<!-- 指定rm1的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop101</value>
</property>
<!-- 指定rm1的web端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hadoop101:8088</value>
</property>
<!-- 指定rm1的内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hadoop101:8032</value>
</property>
<!-- 指定AM向rm1申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hadoop101:8030</value>
</property>
<!-- 指定供NM连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hadoop101:8031</value>
</property>
<!-- rm2的配置 -->
<!-- 指定rm2的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop102</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>hadoop102:8088</value>
</property>
<property>
<name>yarn.resourcemanager.address.rm2</name>
<value>hadoop102:8032</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>hadoop102:8030</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm2</name>
<value>hadoop102:8031</value>
</property>
<!-- 指定zookeeper集群的地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop101:2181,hadoop102:2181,hadoop103:2181</value>
</property>
<!-- 启用自动故障转移机制 -->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<!-- 指定resourcemanager的状态信息存储在zookeeper集群 -->
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</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>
<!-- yarn容器允许分配的最大最小内存 -->
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>512</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>4096</value>
</property>
<!-- yarn容器允许管理的物理内存大小 -->
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>4096</value>
</property>
<!-- 关闭yarn对物理内存和虚拟内存的限制检查 -->
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
<!-- 开启日志聚集功能 -->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<!-- 设置日志聚集服务器地址 -->
<property>
<name>yarn.log.server.url</name>
<value>http://hadoop101:19888/jobhistory/logs</value>
</property>
<!-- 设置日志保留时间为7天 -->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
</configuration>
3. 启停
四.3.(2)启停脚本
脚本使用了一个自己编写的zookeeper启停脚本
# 置于用户目录下的bin文件夹中,文件名为hadoop-ha.sh
vim ~/bin/hadoop-ha.sh
# 以下是脚本内容
#!/bin/bash
if [[ $# -ne 1 ]]
then
echo "usage: hadoop-ha.sh (format|start|stop)"
exit
fi
case $1 in
"format")
line=$(cat -n $HADOOP_HOME/etc/hadoop/hdfs-site.xml | tr -s ' \t' | awk '/dfs\.namenode\.shared\.edits\.dir/{print $1+1}')
for host in $(cat -n $HADOOP_HOME/etc/hadoop/hdfs-site.xml | tr -s ' \t' | awk -vline=$line 'FNR==line{print $2}' | grep -E -o '([^/]+:[0-9]+)+' | awk -vRS=';' '{print $0}' | awk -F':' '{print $1}' | grep -E '\S')
do
ssh $host "rm -rf $HADOOP_HOME/data $HADOOP_HOME/logs"
ssh $host "hdfs --daemon start journalnode"
done
namenodeMachine=""
for host in $(cat -n $HADOOP_HOME/etc/hadoop/hdfs-site.xml | tr -s ' \t' | awk -vline=$line 'FNR==line{print $2}' | grep -E -o '([^/]+:[0-9]+)+' | awk -vRS=';' '{print $0}' | awk -F':' '{print $1}' | grep -E '\S')
do
if [[ $(ping -W1 -c1 $host &>/dev/null;echo $?) -eq 0 ]]
then
if [[ -z "$namenodeMachine" ]]
then
namenodeMachine=$host
ssh $host "hdfs namenode -format"
ssh $host "hdfs --daemon start namenode"
else
ssh $host "hdfs namenode -bootstrapStandby"
fi
fi
done
for host in $(cat -n $HADOOP_HOME/etc/hadoop/hdfs-site.xml | tr -s ' \t' | awk -vline=$line 'FNR==line{print $2}' | grep -E -o '([^/]+:[0-9]+)+' | awk -vRS=';' '{print $0}' | awk -F':' '{print $1}' | grep -E '\S')
do
ssh $host "hdfs --daemon stop journalnode"
done
ssh $namenodeMachine "hdfs --daemon stop namenode"
zookeeper.sh start
echo "Y" | hdfs zkfc -formatZK
zookeeper.sh stop
;;
"start"|"stop")
line=$(cat $HADOOP_HOME/etc/hadoop/yarn-site.xml | awk '{ \
i=match($0,"yarn\.log\.server\.url"); \
if(i!=0){ \
getline; \
gsub("\\s",""); \
print $0; \
} \
}')
line=${line#*//}
historyServerMachine=$(echo ${line%%:*})
zookeeper.sh $1
$1-dfs.sh
$1-yarn.sh
ssh $historyServerMachine "mapred --daemon $1 historyserver"
;;
*)
echo "usage: hadoop-ha.sh (format|start|stop)"
;;
esac
# 赋予执行权限
chmod +x ~/bin/hadoop-ha.sh
四.3.(3)格式化并启动
# 格式化
hadoop-ha format
# 启动
hadoop-ha start
# 停止
hadoop-ha stop
四.4查看网页端
Web查看目标 访问网址
NameNode http://hadoop101:9870 http://hadoop102:9870 http://hadoop103:9870
Resource Manager http://hadoop101:8088 http://hadoop102:8088
历史服务器 http://hadoop101:19888/jobhistory