Hadoop HDFS-HA
HA(High Availablity)
1.高可用:7*24小时不中断服务。
2.实现高可用最关键的策略是消除单点故障(一个节点故障,整个集群不可以使用),HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA。
3.NameNode主要在以下两个方法影响HDFS集群
NameNode集群发生意外,如宕机,集群将无法使用,直到管理员重启。
NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用
HDFS HA 功能通过配置多个NameNodes(1个Active/多个Standby)实现在集群中对NameNode的热备份来解决问题。如果出现故障可以将Standby替换Active。
HDFS-HA 集群搭建
当前HDFS集群的规划
HA的主要目的是消除NameNode的单点故障,需要将HDFS集群重新规划,这里规划3个。
HDFS-HA 核心问题
1.如何保证三台NameNode的数据一致
Fsimage:需要一台NameNode作为Active生成数据,其他NameNode作为Standby进行同步
Edits:需要引进新的模块JournaNode来保证edtis的文件数据一致性
2.怎么让只有一台nn是active,其他所有是standly
1.手动分配,指定某一台为active,其余为standly
2.自动分配
3.2nn在ha架构中不允许不存在,那么谁负责定期合并Fsimage和Edits?
由standly的nn
4.如果active的nn发生了问题,怎么让其他的nn变成新的active?
a.手动故障转移
b.自动故障转移:依赖框架
HDFS-HA手动配置
1 环境准备
1.修改IP
2.修改主机名和主机名与IP地址的映射
3.关闭防火墙
4.ssh免密登录
5.安装JDK,配置环境变量等
我之前已经配过了,具体流程可以看下面的博客
https://www.cnblogs.com/rananie/p/14802251.html
https://www.cnblogs.com/rananie/p/14897536.html
2 规划集群
3 配置HDFS-HA集群
1.在opt目录下创建一个ha文件,103、104同样需要
[ranan@hadoop102 opt]$ sudo mkdir ha
[ranan@hadoop102 opt]$ ll
总用量 0
drwxr-xr-x. 2 root root 6 1月 5 10:28 ha # 权限属于root用户
drwxr-xr-x. 4 ranan ranan 46 6月 17 2021 module
drwxr-xr-x. 2 ranan ranan 67 7月 8 21:34 software
[ranan@hadoop102 opt]$ sudo chown ranan:ranan ha # 修改权限
[ranan@hadoop102 opt]$ ll
总用量 0
drwxr-xr-x. 2 ranan ranan 6 1月 5 10:28 ha
drwxr-xr-x. 4 ranan ranan 46 6月 17 2021 module
drwxr-xr-x. 2 ranan ranan 67 7月 8 21:34 software
2.将/opt/module/下的hadoop-3.1.3拷贝到/opt/ha目录下
[ranan@hadoop102 opt]$ cp -r /opt/module/hadoop-3.1.3 /opt/ha/
3.删除/opt/ha/hadoop-3.1.3 下的data和logs文件,删除数据
[ranan@hadoop102 hadoop-3.1.3]$ rm -rf data/ logs/
4.配置/opt/ha/hadoop-3.1.3/etc/hadoop/目录下的core-site.xml
和hdfs-site.xml
<!-- core-site.xml -->
<configuration>
<!-- 指定 NameNode 的地址 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value> <!--不需要单独指定一个节点为NameNode,我们访问的是mycluster,访问代理类来处理访问让访问连接到active节点-->
</property>
<!-- 指定 hadoop 数据的存储目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/ha/hadoop-3.1.3/data</value>
</property>
</configuration>
<!--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>file://${hadoop.tmp.dir}/jn</value>
</property>
<!-- 完全分布式集群名称 -->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value> <!--与core-site.xml里面的fs.defaultFS设置一致-->
</property>
<!--集群中的NameNode节点都有哪些 -->
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2,nn3</value>
</property>
<!--NameNode的RPC内部通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name> <!--与上述设置的集群中的namenode一致-->
<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>
<!--NameNode的http外部通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name> <!--与上述设置的集群中的namenode一致-->
<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>
<!-- 指定 NameNode 元数据在 JournalNode 上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop102:8485;hadoop103:8485;hadoop104:8485/mycluster</value>
</property>
<!-- 访问代理类: client用于确定哪个NameNode为Active,客户端访问mycluster集群,并不知道哪个节点是active,由代理类帮客户连接到active-->
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制,即同一时刻只能有一个NameNode对外响应 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<!-- 使用隔离机制时需要 ssh 无秘钥登录,自动故障转移时用到-->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/ranan/.ssh/id_rsa</value>
</property>
</configuration>
5.分发配置信息
[ranan@hadoop102 opt]$ xsync ha/hadoop-3.1.3
4 启动HDFS-HA集群
1 修改3台节点的环境配置信息,关于hadoop的配置信息,我的在/etc/profile.d/my_env.sh
[ranan@hadoop103 hadoop-3.1.3]$ cd /etc/profile.d
[ranan@hadoop103 profile.d]$ sudo vim my_env.sh
[ranan@hadoop102 profile.d]$ source /etc/profile # 会重新加载profile脚本,该脚本里会加载profile.d
2 在各个JournalNode节点上,启动JournalNode服务
[ranan@hadoop102 hadoop-3.1.3]$ hdfs --daemon start journalnode
[ranan@hadoop103 hadoop-3.1.3]$ hdfs --daemon start journalnode
[ranan@hadoop104 hadoop-3.1.3]$ hdfs --daemon start journalnode
[ranan@hadoop102 hadoop]$ jpsall
=============== hadoop102 ===============
4005 Jps
3933 JournalNode
=============== hadoop103 ===============
3738 Jps
3679 JournalNode
=============== hadoop104 ===============
3699 JournalNode
3757 Jps
3 在启动集群之前,需要格式化namenode,但是现在三台节点都是namenode,我们可以随便选择一个节点格式化,其他节点同步该信息,namenode需要一致
在nn1,对其格式化,并启动
[ranan@hadoop102 hadoop]$ hadfs namenode -farmat
[ranan@hadoop102 hadoop]$ hdfs --daemon start namenode
查看是否启动成功:http://hadoop102:9870/
在nn2和nn3上,同步nn1的元数据信息
[ranan@hadoop103 hadoop-3.1.3]$ hdfs namenode -bootstrapStandby
[ranan@hadoop104 hadoop-3.1.3]$ hdfs namenode -bootstrapStandby
[ranan@hadoop103 hadoop-3.1.3]$ hdfs --daemon start namenode
[ranan@hadoop104 hadoop-3.1.3]$ hdfs --daemon start namenode
查看是否启动成功:http://hadoop103:9870/,http://hadoop104:9870/
4 修改其中一个节点为Active节点
因为这是我们手动配置的,所以所有节点都是standby,我们需要手动的修改其中一个为Active节点
先在所有节点上,启动datanode,将HDFS启动起来
[ranan@hadoop102 hadoop-3.1.3]$ hdfs --daemon start datanode
[ranan@hadoop103 hadoop-3.1.3]$ hdfs --daemon start datanode
[ranan@hadoop104 hadoop-3.1.3]$ hdfs --daemon start datanode
[ranan@hadoop102 hadoop]$ jpsall
=============== hadoop102 ===============
4200 NameNode
4570 DataNode
4747 Jps
3933 JournalNode
=============== hadoop103 ===============
3976 NameNode
4408 Jps
4238 DataNode
3679 JournalNode
=============== hadoop104 ===============
3699 JournalNode
4259 DataNode
3990 NameNode
4427 Jps
将nn1切换为Active
[ranan@hadoop102 hadoop]$ hdfs haadmin -transitionToActive nn1
5 假设nn1挂掉了
kill nn1
[ranan@hadoop102 hadoop]$ jpsall
=============== hadoop102 ===============
4200 NameNode
4570 DataNode
19355 Jps
3933 JournalNode
=============== hadoop103 ===============
3976 NameNode
18923 Jps
4238 DataNode
3679 JournalNode
=============== hadoop104 ===============
3699 JournalNode
4259 DataNode
3990 NameNode
19033 Jps
[ranan@hadoop102 hadoop]$ kill -kill 4200
[ranan@hadoop102 hadoop]$ jpsall
=============== hadoop102 ===============
4570 DataNode
3933 JournalNode
19422 Jps
=============== hadoop103 ===============
18992 Jps
3976 NameNode
4238 DataNode
3679 JournalNode
=============== hadoop104 ===============
3699 JournalNode
4259 DataNode
3990 NameNode
19103 Jps
假设此时我们把nn2设置为active,报错102拒绝连接
[ranan@hadoop103 hadoop-3.1.3]$ hdfs haadmin -transitionToActive nn2
2022-01-11 10:10:18,292 INFO ipc.Client: Retrying connect to server: hadoop102/192.168.10.102:8020. Already tried 0 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=1, sleepTime=1000 MILLISECONDS)
Unexpected error occurred Call From hadoop103/192.168.10.103 to hadoop102:8020 failed on connection exception: java.net.ConnectException: 拒绝连接; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused
Usage: haadmin [-ns <nameserviceId>] [-transitionToActive [--forceactive] <serviceId>]
重启nn1,发现nn1变成了standby,现在没有active了,可以重新选取节点成为新的active
[ranan@hadoop102 hadoop]$ hdfs --daemon start namenode
手动模式下,需要所有namenode启动才可以将某个节点转成Active
Active需要知道其他namenode是存活状态,因为一个集群中只能由一个Active,如果联系不上,不知道该节点是否是active。
HDFS-HA自动模式
HDFS-HA 自动故障转移工作机制
主要需要解决的问题:当要提升某个节点为Active的时候,如果确定其他节点不是Active
ZooKeeper 是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务
自动故障增加了两个新组件:Zookeeper和ZKFailoverController(ZKFC)进程,该进程监控节点是否挂掉,如果监控到挂点了,再次发送kill命令真正杀死节点,防止出现脑裂。
HDFS-HA 自动故障转移的集群规划
配置HDFS-HA 自动故障转移
1 在hdfs-site.xml里面打开自动转移
<!--打开自动转移-->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
2 在core-site.xml里面添加zookeeper信息
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
</property>
3 分发节点
[ranan@hadoop102 hadoop]$ xsync core-site.xml hdfs-site.xml
4 保持集群关闭状态下,启动Zookeeper集群,再初始化HA在Zookeeper中状态
# 启动zookeep
[ranan@hadoop102 zookeeper-3.4.10]# zkServer.sh start
[ranan@hadoop103 zookeeper-3.4.10]# zkServer.sh start
[ranan@hadoop104 zookeeper-3.4.10]# zkServer.sh start
# 初始化HA在Zookeeper中的状态
[ranan@hadoop102 zookeeper-3.4.10]# hdfs zkfc -formatZK
5 启动集群
[ranan@hadoop102 hadoop]# start-dfs.sh
6 可以去zkCli.sh客户端查看NameNode节点内容
哪台机器先启动DFSZK Failover Controller,哪个机器的NameNode就是Active NameNode
[ranan@hadoop102 zookeeper]# bin/zkcli.sh
get -s /hadoop-ha/mycluster/ActiveStandbyElectorLock
mycluster nn2 hadoop103 # 这里是hadoop103节点
7 杀死Hadoop103,观察Active是否转移
Active切换到hadoop102后,如果hadoop103重新启动,hadoop103不再是Active而是Standby
[ranan@hadoop103 zookeeper]# kill -9 4897
# zkcli.sh客户端查看
get -s /hadoop-ha/mycluster/ActiveStandbyElectorLock
mycluster nn1 hadoop102 # 这里切换到了hadoop102了
注意如果写代码上传到比如根目录使用hdfs://mycluster/
在上传过程中会去找active,所以可能在尝试中会连接到standby,有报错但是没关系。
YARN-HA配置
YARN-HA 工作机制
配置YARN-HA集群
1 集群规划
2 核心问题
a.如果当前active rm挂了,其他rm怎么上位
核心原理和hdfs一样,利用了zk的临时节点
b.当前rm上有很多的计算程序在等待运行,其他rm怎么将这些程序接手过来继续跑
rm会将当前的所有计算程序的状态存储在zk中,其他rm上位后会去读取,然后接着跑
3 修改yarn-site.xml,修改之后分发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>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2,rm3</value>
</property>
<!--rm1的配置-->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop102</value><!--指定rm1 的主机名-->
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hadoop102:8088</value><!--指定rm1的web端地址-->
</property>
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hadoop102:8032</value><!--指定rm1的内部通信地址-->
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hadoop102:8030</value><!--指定AM向rm1申请资源的地址-->
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hadoop102:8031</value><!--指定供NM连接的地址-->
</property>
<!--rm2的配置-->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop103</value><!--指定rm2 的主机名-->
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hadoop103:8088</value><!--指定rm2的web端地址-->
</property>
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hadoop103:8032</value><!--指定rm2的内部通信地址-->
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hadoop103:8030</value><!--指定AM向rm2申请资源的地址-->
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hadoop103:8031</value><!--指定供NM连接的地址-->
</property>
<!--rm3的配置-->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop104</value><!--指定rm3 的主机名-->
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hadoop104:8088</value><!--指定rm3的web端地址-->
</property>
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hadoop104:8032</value><!--指定rm3的内部通信地址-->
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hadoop104:8030</value><!--指定AM向rm3申请资源的地址-->
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hadoop104:8031</value><!--指定供NM连接的地址-->
</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,HADDOP_COMMON_HOME,HADOOP_HDFS_HOME,HADDOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAORED_HOME</value>
</property>
</configuration>
4 启动yarn
[ranan@hadoop102 hadoop]$ start-yarn.sh
# 查看服务状态
[ranan@hadoop102 hadoop]$ yarn rmadmin -getServiceState rm1
standby
访问hadoop102:8088发现直接跳到了hadoop103:8088,因为这里hadoop103:8088是Active。