写在前面
本文为hadoop系列博客最后一篇博客,下篇博客开启Hive篇章,敬请期待。那这篇博客讲了个什么事呢?白话一下:就是HDFS和Yarn在集群里只能有一个namenode和resourcemanager,那么如果有一天他俩挂了,我们究竟要怎么做,才能使新的namenode或resourcemanager以最短的时间接管集群。大多数情况下我们会启动一个 NameNode 的热备(Warm standby )节点。也就是说当主节点不能正常服务时,由热备节点进行接替。此时主备节点切换时间为服务恢复时间,服务恢复时间越短高可用性越大(HA越大)。
一,概述
HA 的英文全称是 High Availability,中文翻译为高可用性。HA 的定义为 系统对外正常提供服务时间的百分比。
实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA。即 NameNode HA with QJM和ResourcesManager HA
具体来说,集群的可靠性可用平均无故障时间(MTTF)来度量,即集群正常服务的平均运行时间,集群的可维护性用平均维修时间(MTTR)来度量,即集群从不能正常服务到重新正常服务所需要的平均维修时间。
因此 HA 可精确定义为:MTTF/(MTTF+MTTR) * 100%
1.NameNode HA
HDFS HA功能通过NameNode的热备来解决故障问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将热备NameNode很快的切换到另外一台机器。
那么要实现主备节点的切换,就要对传统的框架进行一些改变:
- 元数据管理方法
需要两个namenode来分别做主备节点(zookeeper的去集群中心化) - 增加一个状态管理功能模块
就是说得有一个进程来管理namenode的状态,判断他是否在正常运行(zookeeper的zkfailover进程) - 保证两个主备NameNode之间能够ssh无密码登录
- 隔离(Fence),即同一时刻仅仅有一个NameNode对外提供服务(两个namenode同时工作的情况称为脑裂现象)
主备节点切换的细节
- 故障检测
集群中的每个NameNode在ZooKeeper中维护了一个会话,如果机器崩溃,ZooKeeper中的会话将终止,ZooKeeper通知另一个NameNode需要触发故障转移。 - 现役namenode选择
ZooKeeper提供了一个简单的机制用于唯一的选择一个节点为active状态。如果目前现役NameNode崩溃,另一个节点可能从ZooKeeper获得特殊的排外锁以表明它应该成为现役NameNode。
ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。每个运行NameNode的主机也运行了一个ZKFC进程。
ZKFC负责: - 健康监测
ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非健康的。 - ZooKeeper会话管理
当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点的支持,如果会话终止,锁节点将自动删除。 - 基于ZooKeeper的选择
如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,它将为自己获取该锁。如果成功,则它已经赢得了选择,并负责运行故障转移进程以使它的本地NameNode为Active。
2.ResourceManager HA
官方文档链接如下:http://hadoop.apache.org/docs/r3.1.3/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html
RM可以选择嵌入基于Zookeeper的ActiveStandbyElector,以确定哪个RM应该是Active。当Active发生故障或无响应时,另一个RM将自动被选为Active,然后接管。请注意,不需要像HDFS那样运行单独的ZKFC守护程序,因为嵌入在RM中的ActiveStandbyElector充当故障检测器和领导者选举者,而不是单独的ZKFC守护进程。
思考一下,为啥Yarn有内嵌故障检测器,而HDFS没有呢?(是因为第一代hadoop里mapreduce包含了分布式计算和资源调配的功能,到了第二代把mapreduce的资源调配功能分离了出来做成了yarn,在第二代hadoop发行的时候,zookeeper也在发行,这时候一些大神就把ZKFC的函数直接加在yarn上了。)
二,Namenode HA搭建
- 在/opt下新建ha目录,并将hadoop安装包拷贝一份
sudo mkdir /opt/ha
sudo chown atguigu:atguigu /opt/ha
cp -r /opt/module/hadoop-3.1.3 /opt/ha
rm -rf /opt/ha/hadoop-3.1.3/data /opt/ha/hadoop-3.1.3/logs
- 修改/opt/ha/hadoop-3.1.3的配置文件
- core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/ha/hadoop-3.1.3/data</value>
</property>
<property>
<name>hadoop.proxyuser.atguigu.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.atguigu.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.http.staticuser.user</name>
<value>atguigu</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
</property>
</configuration>
- hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2, nn3</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>hadoop102:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>hadoop103:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn3</name>
<value>hadoop104:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>hadoop102:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>hadoop103:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn3</name>
<value>hadoop104:9870</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>${hadoop.tmp.dir}/jn</value>
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop102:8485;hadoop103:8485;hadoop104:8485/mycluster</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/atguigu/.ssh/id_ecdsa</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
</configuration>
- 发送hadoop到所有 节点
sudo xsync /opt/ha
- 修改环境变量
#HADOOP_HOME
export HADOOP_HOME=/opt/ha/hadoop-3.1.3
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
sudo xsync /etc/profile.d/my_env.sh
source一下或者重启session
- 启动JournalNode
在任意一台节点执行
hdfs --workers --daemon start journalnode
- 32格式化NN
第五步执行完后,等一段时间再格式化。
hdfs --workers --daemon start journalnode
- 33,34同步32的元数据
在33,34上执行同步命令,并启动Namenode
hdfs namenode -bootstrapStandby
hdfs --daemon start namenode
- 初始化zkfc在zookeeper中的节点
先启动zookeeper集群 后,在任意一台节点格式化zkfc
hdfs zkfc -formatZK
- 启动zkfc
在32,33,34上分别启动zkfc
hdfs --daemon start zkfc
- 启动datanodes
在任意一节点执行
hdfs --workers --daemon start datanode
- 假设出了问题,想重新来,怎么办
- 关闭集群,在所有节点执行
killall -9 java
- 在所有节点删除data logs文件夹
rm -rf /opt/ha/hadoop-3.1.3/data /opt/ha/hadoop-3.1.3/logs
- 启动Zookeeper集群
- 执行第5,6,7,9,10步
三,Yarn HA搭建
- 修改配置文件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>
<!-- 声明两台resourcemanager的地址 -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>cluster-yarn1</value>
</property>
<!--指定resourcemanager的逻辑列表-->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- ========== rm1的配置 ========== -->
<!-- 指定rm1的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop102</value>
</property>
<!-- 指定rm1的web端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hadoop102:8088</value>
</property>
<!-- 指定rm1的内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hadoop102:8032</value>
</property>
<!-- 指定AM向rm1申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hadoop102:8030</value>
</property>
<!-- 指定供NM连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hadoop102:8031</value>
</property>
<!-- ========== rm2的配置 ========== -->
<!-- 指定rm2的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop103</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>hadoop103:8088</value>
</property>
<property>
<name>yarn.resourcemanager.address.rm2</name>
<value>hadoop103:8032</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>hadoop103:8030</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm2</name>
<value>hadoop103:8031</value>
</property>
<!-- 指定zookeeper集群的地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop102:2181,hadoop103:2181,hadoop104: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>
</configuration>
- 同步更新其他节点的配置信息,分发配置文件
xsync hadoop/
然后启动hdfs,启动yarn
写在最后
在网页端查看其状态,我这里就直截图HDFS的了,Yarn的比较好玩(坏笑)我就不截图了。
请杀掉正在运行的主namenode,查看下一个主namenode。