HA 概述
1)所谓 HA(High Availablity),即高可用(7*24 小时不中断服务)。
2)实现高可用最关键的策略是消除单点故障(传统的主从模式集群单个节点发生故障会影响整个集群)。HA 严格来说应该分成各个组件的 HA 机制:HDFS 的 HA 和 YARN 的 HA。
3)NameNode 主要在以下两个方面影响 HDFS 集群
- NameNode 机器发生意外,如宕机,集群将无法使用,直到管理员重启
- NameNode 机器需要升级,包括软件、硬件升级,此时集群也将无法使用
- HDFS HA 功能通过配置多个 NameNode(Active/Standby)实现在集群中对 NameNode 的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可以启动另一台机器上的 NameNode 继续维护整个集群的运行(集群中同时只能有一台 active 的 NN,其他 NN 处于 standby(备用) )。而这种启动方式分为手动和自动(推荐),但是在这之前,我们必须通过某种方式保证所有 NN 的元数据一致,这样才能保证 active 状态的 NN 故障后,另一个处于 standby 状态的 NN 激活为 active 能够正常维持集群运行,类似于公司员工的任务的交接。
HDFS 高可用
保证所有 NN 的数据一致性
在处于 active 的 NN 正常运行时,他会生成 Fsimage 文件,让其他处于 standby 的 NN 同步,同时引入 JournalNode 节点来保证 edits 文件数据的一致性,JournalNode 作为 active 的 NN 和 standby 的 NN 的中间节点,activeNN 会把 edits 发送给 JournalNode,然后 standbyNN 从 JournalNode 获取 edits。同时为了保证 JournalNode 的可靠性,JournalNode 本身也是一个多节点的集群。
JournalNode 节点会在集群自动的选择一个"主"节点出来,Active 节点会和 JournalNode 的主节点通信,然后 JournalNode 集群的主节点会将数据发送给其他的节点,只要有过半的节点完成了数据的存储(过半写成功),JournalNode 集群的主节点,就会将成功信息返回给 Active 节点。当 JournalNode 集群的主节点挂掉,其他的 JournalNode 节点会快速选举出新的"主"节点来。
同时在 HA 架构中,并没有 SecondaryNameNode,那么定期合并 fsimage 的 eedits 的任务是由 standby 的 NN 来完成的。
手动模式
配置 core-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<configuration>
<!-- 指定hdfs的nameservice为ns1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster/</value>
</property>
<!-- 指定hadoop临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value></value>
</property>
</configuration>
|
配置 hdfs-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
<configuration>
<!--指定hdfs的nameservice为mycluster,需要和core-site.xml中的保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<!-- hadoop-ha下面有两个NameNode,分别是nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>linux01:8020</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>linux01:9870</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>linux02:8020</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>linux02:9870</value>
</property>
<!-- nn3的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn3</name>
<value>linux03:8020</value>
</property>
<!-- nn3的http通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn3</name>
<value>linux03:9870</value>
</property>
<!-- 指定NameNode的edits元数据在JournalNode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://linux01:8485;linux02:8485;linux03:8485/mycluster</value>
</property>
<!-- 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}/data</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>
<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
</configuration>
|
HA 集群的相关文件配置省略。以 3 台服务器的 HA 为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
在各个节点上,输入以下命令启动该节点的journalNode服务:
hdfs --daemon start journalnode
在NN1上进行格式化并启动
hdfs namenode -format
hdfs --daemon start namenode
分别在NN2和NN3上运行如下命令,同步NN1的元数据信息
hdfs namenode -bootstrapStandby
启动NN2,NN3
hdfs --daemon start namenode
此时所有NN处于standby,启动所有节点的datanode
hdfs --daemon start datanode
切换NN1为active
hdfs haadmin start -transitionToActive linux01
|
修改后重新分发文件!

自动模式
自动模式需要引入 zookeeper 和 ZKFailoverController(ZKFC)
配置 hdfs-site.xml
1
2
3
4
5
|
<!-- 启用 nn 故障自动转移 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
|
配置 core-site.xml
1
2
3
4
5
|
<!-- 指定 zkfc 要连接的 zkServer 地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>linux01:2181,linux02:2181,linux03:2181</value>
</property>
|
修改后重新分发文件!
1
2
3
4
5
6
7
8
|
在每台服务器运行以下命令启动zookeeper集群:
zkServer.sh start
启动后初始化HA在zookeeper中的状态:
hdfs zkfc -formatZK
杀死active namenode查看是否有standby namenode激活:
kill -9 namenode的进程id
运行zkCli.sh查看namenode选举内容:
zkCli.sh
|

解决 NN 连接不上 JN 的问题
自动故障转移配置好以后,然后使用 start-dfs.sh 群起脚本启动 hdfs 集群,有可能 会遇到 NameNode 起来一会后,进程自动关闭的问题。查看 NameNode 日志,报错信息如下:
查看报错日志,可分析出报错原因是因为 NameNode 连接不上 JournalNode,而利 用 jps 命令查看到三台 JN 都已经正常启动,为什么 NN 还是无法正常连接到 JN 呢?这 是因为 start-dfs.sh 群起脚本默认的启动顺序是先启动 NN,再启动 DN,然后再启动 JN, 并且默认的 rpc 连接参数是重试次数为 10,每次重试的间隔是 1s,也就是说启动完 NN 以后的 10s 中内,JN 还启动不起来,NN 就会报错了。
core-default.xml 里面有两个参数如下:
1
2
3
4
5
6
7
8
9
10
|
<!--NN连接JN重试次数,默认10次-->
<property>
<name>ipc.client.connect.max.retries</name>
<value>10</value>
</property>
<!--重试时间间隔,默认1s-->
<property>
<name>ipc.client.connect.retry.interval</name>
<value>1000</value>
</property>
|
解决方案:可以先 JN 成功启动,然后启动三台 NN 或者 在 core-site.xml 调大上面的参数:
1
2
3
4
5
6
7
8
9
10
|
<!--NN连接JN重试次数,默认10次-->
<property>
<name>ipc.client.connect.max.retries</name>
<value>20</value>
</property>
<!--重试时间间隔,默认1s-->
<property>
<name>ipc.client.connect.retry.interval</name>
<value>5000</value>
</property>
|

Yarn 高可用

核心问题
1
2
3
4
|
如果当前 active rm 挂了,其他 rm 怎么将其他 standby rm 上位
核心原理跟 hdfs 一样,利用了 zk 的临时节点
当前 rm 上有很多的计算程序在等待运行,其他的 rm 怎么将这些程序接手过来接着跑
rm会将当前的所有计算程序的状态存储在 zk 中,其他 rm 上位后会去读取,然后接着跑
|
配置 yarn-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
<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,rm3</value>
</property>
<!-- ========== rm1 的配置 ========== -->
<!-- 指定 rm1 的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>linux01</value>
</property>
<!-- 指定 rm1 的 web 端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>linux01:8088</value>
</property>
<!-- 指定 rm1 的内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>linux01:8032</value>
</property>
<!-- 指定 AM 向 rm1 申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>linux01:8030</value>
</property>
<!-- 指定供 NM 连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>linux01:8031</value>
</property>
<!-- ========== rm2 的配置 ========== -->
<!-- 指定 rm2 的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>linux02</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>linux02:8088</value>
</property>
<property>
<name>yarn.resourcemanager.address.rm2</name>
<value>linux02:8032</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>linux02:8030</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm2</name>
<value>linux02:8031</value>
</property>
<!-- ========== rm3 的配置 ========== -->
<!-- 指定 rm3 的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm3</name>
<value>linux03</value>
</property>
<!-- 指定 rm3 的 web 端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm3</name>
<value>linux03:8088</value>
</property>
<!-- 指定 rm3 的内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm3</name>
<value>linux03:8032</value>
</property>
<!-- 指定 AM 向 rm3 申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm3</name>
<value>linux03:8030</value>
</property>
<!-- 指定供 NM 连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm3</name>
<value>linux03:8031</value>
</property>
<!-- 指定 zookeeper 集群的地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>linux01:2181,linux02:2181,linux03: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.ZKRMStateSt
ore</value>
</property>
<!-- 环境变量的继承 -->
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLAS
SPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
</configuration>
|
配置后重新分发配置文件!
1
2
3
4
5
6
7
|
启动Yarn
start-yarn.sh
查看服务状态
yarn rmadmin -getServiceState rm1
运行zkCli.sh查看RM选举内容
zkCli.sh
可以通过8088端口查看Yarn状态
|
HA 最终规划

以上来自尚硅谷 Hadoop HA 高可用