前言:环境基于nfs文件共享,server1上安装了hadoop,部署的相关服务参考我的上一篇博客
环境 | RHEL 7.3 |
---|---|
h1 | 172.25.1.1(server1) |
h2 | 172.25.1.5(server5) |
DN1 | 172.25.1.2(server2) |
DN2 | 172.25.1.3(server3) |
DN3 | 172.25.1.4(server4) |
在典型的 HA 集群中,通常有两台不同的机器充当 NN。在任何时间,只有一台机器处于Active 状态;另一台机器是处于 Standby 状态。Active NN 负责集群中所有客户端的操作;而 Standby NN 主要用于备用,它主要维持足够的状态,如果必要,可以提供快速的故障恢复。
为了让 Standby NN 的状态和 Active NN 保持同步,即元数据保持一致,它们都将会和JournalNodes 守护进程通信。当 Active NN 执行任何有关命名空间的修改,它需要持久化到一半以上的 JournalNodes 上(通过 edits log 持久化存储),而 Standby NN 负责观察 edits log的变化,它能够读取从 JNs 中读取 edits 信息,并更新其内部的命名空间。一旦 Active NN出现故障,Standby NN 将会保证从 JNs 中读出了全部的 Edits,然后切换成 Active 状态。Standby NN 读取全部的 edits 可确保发生故障转移之前,是和 Active NN 拥有完全同步的命名空间状态。
为了提供快速的故障恢复,Standby NN 也需要保存集群中各个文件块的存储位置。为了实现这个,集群中所有的 Database 将配置好 Active NN 和 Standby NN 的位置,并向它们发送块文件所在的位置及心跳,如下图所示:
在任何时候,集群中只有一个 NN 处于 Active 状态是极其重要的。否则,在两个 Active NN的状态下 NameSpace 状态将会出现分歧,这将会导致数据的丢失及其它不正确的结果。为了保证这种情况不会发生,在任何时间,JNs 只允许一个 NN 充当 writer。在故障恢复期间,将要变成 Active 状态的 NN 将取得 writer 的角色,并阻止另外一个 NN 继续处于 Active状态。
为了部署 HA 集群,你需要准备以下事项:
(1)、NameNode machines:运行 Active NN 和 Standby NN 的机器需要相同的硬件配置;
(2)、JournalNode machines:也就是运行 JN 的机器。JN 守护进程相对来说比较轻量,所以这些守护进程可以可其他守护线程(比如 NN,YARN ResourceManager)运行在同一台机器上。在一个集群中,最少要运行 3 个 JN 守护进程,这将使得系统有一定的容错能力。当然,你也可以运行 3 个以上的 JN,但是为了增加系统的容错能力,你应该运行奇数个 JN(3、5、7 等),当运行 N 个 JN,系统将最多容忍(N-1)/2 个 JN 崩溃。在 HA 集群中,Standby NN 也执行 namespace 状态的 checkpoints,所以不必要运行Secondary NN、CheckpointNode 和 BackupNode;事实上,运行这些守护进程是错误的。
注意:Zookeeper 集群至少三台,总节点数为奇数个。
一、hdfs实现hadoop+zookeeper的高可用
1.新开一个服务器server5并安装nfs-util,
[root@server5 ~]# yum install nfs-utils -y
2.新建hadoop用户:
[root@server5 ~]# useradd hadoop
3.然后在五个服务端开启nfs服务,在server2、server3、server4、server5端将172.25.1.1:/home/hadoop目录挂载到本机/home/hadoop目录下
[root@server5 ~]# systemctl start rpcbind
[root@server5 ~]# systemctl start nfs
[root@server5 ~]# mount 172.25.1.1:/home/hadoop/ /home/hadoop/
4.为了实验环境的干净,在五个服务端将之前的环境清理(不是必须):
[hadoop@server1 hadoop]$ sbin/stop-yarn.sh
[hadoop@server1 hadoop]$ sbin/stop-dfs.sh
##1-5server都执行
[hadoop@server1 hadoop]$ rm -fr /tmp/*
5.在server1端,切换到hadoop用户,解压zookeeper安装包并将zoo_sample.cfg复制为zoo.cfg文件:
由于其他主机都使用了server1端的nfs文件系统,所以在server1端根目录下的hadoop目录里的所有操作,都会同步到其他4台主机里,也就是说5台机器的/home/hadoop目录内容完全一致。
[hadoop@server1 ~]$ tar zxf zookeeper-3.4.9.tar.gz
[hadoop@server1 ~]$ cd zookeeper-3.4.9
[hadoop@server1 zookeeper-3.4.9]$ cp conf/zoo_sample.cfg conf/zoo.cfg
[hadoop@server1 zookeeper-3.4.9]$ ls conf/
configuration.xsl log4j.properties zoo.cfg zoo_sample.cfg
[hadoop@server1 zookeeper-3.4.9]$
编辑zoo.cfg文件,写入集群的三台设备:
[hadoop@server1 zookeeper-3.4.9]$ cd conf/
[hadoop@server1 conf]$ vim zoo.cfg
server.1=172.25.1.2:2888:3888
server.2=172.25.1.3:2888:3888
server.3=172.25.1.4:2888:3888
6.在三个集群节点:
各节点配置文件相同,并且需要在/tmp/zookeeper 目录中创建 myid 文件,写入一个唯一的数字,取值范围在 1-255。比如:172.25.45.2 节点的 myid 文件写入数字“1”,此数字与配置文件中的定义保持一致,(server.1=172.25.0.2:2888:3888)其它节点依次类推。
[hadoop@server2 conf]$ mkdir /tmp/zookeeper
[hadoop@server3 conf]$ mkdir /tmp/zookeeper
[hadoop@server4 conf]$ mkdir /tmp/zookeeper
[hadoop@server2 conf]$ echo 1 > /tmp/zookeeper/myid
[hadoop@server3 conf]$ echo 2 > /tmp/zookeeper/myid
[hadoop@server4 conf]$ echo 3 > /tmp/zookeeper/myid
[hadoop@server2 zookeeper-3.4.9]$ bin/zkServer.sh start
[hadoop@server3 zookeeper-3.4.9]$ bin/zkServer.sh start
[hadoop@server4 zookeeper-3.4.9]$ bin/zkServer.sh start
[hadoop@server2 zookeeper-3.4.9]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: follower
[hadoop@server3 zookeeper-3.4.9]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: follower
[hadoop@server4 zookeeper-3.4.9]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: leader
发现server4为liader!
7.进入命令行
[hadoop@server2 ~]$ cd zookeeper-3.4.9/bin/
[hadoop@server2 bin]$ ls
README.txt zkCli.cmd zkEnv.cmd zkServer.cmd
zkCleanup.sh zkCli.sh zkEnv.sh zkServer.sh
[hadoop@server2 bin]$ ./zkCli.sh
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 3] ls /zookeeper/quota
[]
[zk: localhost:2181(CONNECTED) 4] get /zookeeper/quota
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 0
二、配置hadoop
在server1端:
1.编辑cpre-site.xml文件
[hadoop@server1 ~]$ cd hadoop/etc/hadoop/
[hadoop@server1 hadoop]$ vim core-site.xml #指定hdfs的namenode为masters 指定zookeeper集群主机地址
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://masters</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>172.25.1.2:2181,172.25.1.3:2181,172.25.1.4:2181</value>
</property>
</configuration>
2.编辑hdfs-site.xml文件:
[hadoop@server1 hadoop]$ vim hdfs-site.xml
18
19 <configuration>
20 <property>
21 <name>dfs.replication</name>
22 <value>3</value>
23 </property>
24 指定 hdfs 的 nameservices 为 masters,和 core-site.xml 文件中的设置保持一致
25 <property>
26 <name>dfs.nameservices</name>
27 <value>masters</value>
28 </property>
29 masters 下面有两个 namenode 节点,分别是 h1 和 h2 (名称可自定义)
30 <property>
31 <name>dfs.ha.namenodes.masters</name>
32 <value>h1,h2</value>
33 </property>
34 指定 h1 节点的 rpc 通信地址
35 <property>
36 <name>dfs.namenode.rpc-address.masters.h1</name>
37 <value>172.25.1.1:9000</value>
38 </property>
39 指定 h1 节点的 http 通信地址
40 <property>
41 <name>dfs.namenode.http-address.masters.h1</name>
42 <value>172.25.1.1:50070</value>
43 </property>
44 指定 h2 节点的 rpc 通信地址
45 <property>
46 <name>dfs.namenode.rpc-address.masters.h2</name>
47 <value>172.25.1.5:9000</value>
48 </property>
49 指定 h2 节点的 http 通信地址
50 <property>
51 <name>dfs.namenode.http-address.masters.h2</name>
52 <value>172.25.1.5:50070</value>
53 </property>
54 指定 NameNode 元数据在 JournalNode 上的存放位置
55 <property>
56 <name>dfs.namenode.shared.edits.dir</name>
57 <value>qjournal://172.25.1.2:8485;172.25.1.3:8485;172.25.1.4:8485/masters</value>
58 </property>
59 指定 JournalNode 在本地磁盘存放数据的位置
60 <property>
61 <name>dfs.journalnode.edits.dir</name>
62 <value>/tmp/journaldata</value>
63 </property>
64 开启 NameNode 失败自动切换
65 <property>
66 <name>dfs.ha.automatic-failover.enabled</name>
67 <value>true</value>
68 </property>
69 配置失败自动切换实现方式
70 <property>
71 <name>dfs.client.failover.proxy.provider.masters</name>
72 <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxy
Provider</value>
73 </property>
74 配置隔离机制方法,每个机制占用一行
75 <property>
76 <name>dfs.ha.fencing.methods</name>
77 <value>
78 sshfence
79 shell(/bin/true)
80 </value>
81 </property>
82 使用 sshfence 隔离机制时需要 ssh 免密码
83 <property>
84 <name>dfs.ha.fencing.ssh.private-key-files</name>
85 <value>/home/hadoop/.ssh/id_rsa</value>
86 </property>
87 配置 sshfence 隔离机制超时时间
88 <property>
89 <name>dfs.ha.fencing.ssh.connect-timeout</name>
90 <value>30000</value>
91 </property>
92 </configuration>
3.编辑文件workers:
[hadoop@server1 hadoop]$ vim workers
172.25.1.2
172.25.1.3
172.25.1.4
4.启动 hdfs 集群(按顺序启动)
1)在三个 DN 上依次启动 zookeeper 集群
[hadoop@server2 zookeeper-3.4.9]$ bin/zkServer.sh start
2)在三个 DN 上依次启动 journalnode(第一次启动 hdfs 必须先启动 journalnode)
cd /home/hadoop/hadoop
在server2上
[hadoop@server2 hadoop]$ sbin/hadoop-daemon.sh start journalnode
[hadoop@server2 hadoop]$ jps
13161 Jps
13131 JournalNode
12927 QuorumPeerMain
在server3上
[hadoop@server3 ~]$ cd hadoop
[hadoop@server3 hadoop]$ sbin/hadoop-daemon.sh start journalnode
[hadoop@server3 hadoop]$ jps
12372 Jps
12183 QuorumPeerMain
12332 JournalNode
在server4上
[hadoop@server4 hadoop]$ pwd
/home/hadoop/hadoop
[hadoop@server4 hadoop]$ sbin/hadoop-daemon.sh start journalnode
[hadoop@server4 hadoop]$ jps
10930 QuorumPeerMain
11125 Jps
11084 JournalNode
[hadoop@server4 hadoop]$
3)在server1格式化 HDFS 集群 Namenode 数据默认存放在/tmp,需要把数据拷到 h2
[hadoop@server1 hadoop]$ bin/hdfs namenode -format
[hadoop@server1 hadoop]$ scp -r /tmp/hadoop-hadoop 172.25.1.5:/tmp
4) 格式化 zookeeper (只需在 h1 上执行即可)
[hadoop@server1 hadoop]$ bin/hdfs zkfc -formatZK
5)启动 hdfs 集群(只需在 h1 上执行即可)
[hadoop@server1 hadoop]$ sbin/start-dfs.sh
6) 查看各节点状态
[hadoop@server1 hadoop]$ jps
22536 DFSZKFailoverController
22587 Jps
22174 NameNode
[hadoop@server2 hadoop]$ jps
13131 JournalNode
13246 DataNode
12927 QuorumPeerMain
13375 Jps
[hadoop@server3 hadoop]$ jps
12576 Jps
12183 QuorumPeerMain
12332 JournalNode
12447 DataNode
[hadoop@server4 hadoop]$ jps
10930 QuorumPeerMain
11192 DataNode
11323 Jps
11084 JournalNode
[hadoop@server5 ~]$ jps
10784 NameNode
10859 DFSZKFailoverController
10988 Jps
测试:
测试故障自动切换
server1端杀掉namennode进程:
[hadoop@server1 hadoop]$ jps
22612 Jps
22536 DFSZKFailoverController
22174 NameNode
[hadoop@server1 hadoop]$ kill -9 22174
杀掉 h1主机的 namenode 进程后依然可以访问,此时 h2转为 active 状态接管 namenode
刷新发现active跳到serverr5上:实现高可用
重新开启server1的namenode:
[hadoop@server1 hadoop]$ pwd
/home/hadoop/hadoop
[hadoop@server1 hadoop]$ sbin/hadoop-daemon.sh start namenode
WARNING: Use of this script to start HDFS daemons is deprecated.
WARNING: Attempting to execute replacement "hdfs --daemon start" instead.
[hadoop@server1 hadoop]$ jps
22774 Jps
22536 DFSZKFailoverController
22702 NameNode
刷新发现server1变成stanby
二、yarn实现hadoop+zookeeper的高可用
1、 编辑 mapred-site.xml 文件 指定 yarn 为 MapReduce 的框架
[hadoop@server1 hadoop]$ cd /home/hadoop/hadoop/etc/hadoop/
[hadoop@server1 hadoop]$ vim mapred-site.xml
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
2、编辑 yarn-site.xml 文件
[hadoop@server1 hadoop]$ vim yarn-site.xml
15<configuration>
配置可以在 nodemanager 上运行 mapreduce 程序
16 <property>
17 <name>yarn.nodemanager.aux-services</name>
18 <value>mapreduce_shuffle</value>
19 </property>
激活 RM 高可用
20 <property>
21 <name>yarn.resourcemanager.ha.enabled</name>
22 <value>true</value>
23 </property>
指定 RM 的集群 id
24 <property>
25 <name>yarn.resourcemanager.cluster-id</name>
26 <value>RM_CLUSTER</value>
27 </property>
定义 RM 的节点
28 <property>
29 <name>yarn.resourcemanager.ha.rm-ids</name>
30 <value>rm1,rm2</value>
31 </property>
指定 RM1 的地址
32 <property>
33 <name>yarn.resourcemanager.hostname.rm1</name>
34 <value>172.25.1.1</value>
35 </property>
指定 RM2 的地址
36 <property>
37 <name>yarn.resourcemanager.hostname.rm2</name>
38 <value>172.25.1.5</value>
39 </property>
激活 RM 自动恢复
40 <property>
41 <name>yarn.resourcemanager.recovery.enabled</name>
42 <value>true</value>
43 </property>
配置 RM 状态信息存储方式,有 MemStore 和 ZKStore
44 <property>
45 <name>yarn.resourcemanager.store.class</name>
46 <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
48 </property>
配置为 zookeeper 存储时,指定 zookeeper 集群的地址
49 <property>
50 <name>yarn.resourcemanager.zk-address</name>
51 <value>172.25.1.2:2181,172.25.1.3:2181,172.25.1.4:2181</value>
52 </property>
53 <!-- Site specific YARN configuration properties -->
54
55 </configuration>
3、启动 yarn 服务
[hadoop@server1 hadoop]$ pwd
/home/hadoop/hadoop
[hadoop@server1 hadoop]$ sbin/start-yarn.sh
Starting resourcemanagers on [ 172.25.1.1 172.25.1.5]
Starting nodemanagers
[hadoop@server1 hadoop]$ jps
3417 DFSZKFailoverController
3803 ResourceManager
3068 NameNode
3934 Jps
4、RM2 上需要手动启动
[hadoop@server5 hadoop]$ pwd
/home/hadoop/hadoop
[hadoop@server5 hadoop]$ sbin/yarn-daemon.sh start resourcemanager
[hadoop@server5 hadoop]$ jps
11329 ResourceManager
10996 DFSZKFailoverController
10933 NameNode
11643 Jps
最好是把 RM 与 NN 分离运行,这样可以更好的保证程序的运行性能。
5、查看各个节点的状态
[hadoop@server1 hadoop]$ jps
13512 Jps
3417 DFSZKFailoverController
3803 ResourceManager
3068 NameNode
[hadoop@server5 hadoop]$ jps
11329 ResourceManager
10996 DFSZKFailoverController
10933 NameNode
11643 Jps
[hadoop@server2 hadoop]$ jps
1556 QuorumPeerMain
11524 NodeManager
11637 Jps
11225 JournalNode
11327 DataNode
[hadoop@server3 hadoop]$ jps
11520 NodeManager
11330 DataNode
11098 QuorumPeerMain
11228 JournalNode
11631 Jps
[hadoop@server4 hadoop]$ jps
2066 Jps
1955 NodeManager
1656 JournalNode
1532 QuorumPeerMain
1758 DataNode
6、测试 yarn 故障切换
[hadoop@server2 hadoop]$ cd
[hadoop@server2 ~]$ cd zookeeper-3.4.9
[hadoop@server2 zookeeper-3.4.9]$ bin/zkCli.sh
[zk: localhost:2181(CONNECTED) 11] get /yarn-leader-election/RM_CLUSTER/ActiveBreadCrumb
RM_CLUSTERrm2
cZxid = 0x100000042
ctime = Wed May 29 10:14:47 CST 2019
mZxid = 0x100000042
mtime = Wed May 29 10:14:47 CST 2019
pZxid = 0x100000042
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 17
numChildren = 0
可以看到我们现在是rm2及172.25.1.5的节点为主节点。
作测试:
[hadoop@server5 hadoop]$ jps
12625 NameNode
13747 Jps
12741 DFSZKFailoverController
13371 ResourceManager
[hadoop@server5 hadoop]$ kill -9 13371
[hadoop@server5 hadoop]$ jps
12625 NameNode
12741 DFSZKFailoverController
13759 Jps
[hadoop@server5 hadoop]$
我们在rm2的这一端。杀掉ResourceManager进程。
[hadoop@server2 bin]$ ./zkCli.sh
[zk: localhost:2181(CONNECTED) 2] get /yarn-leader-election/RM_CLUSTER/ActiveBreadCrumb
RM_CLUSTERrm1
cZxid = 0x100000042
ctime = Wed May 29 10:14:47 CST 2019
mZxid = 0x10000004d
mtime = Wed May 29 10:37:26 CST 2019
pZxid = 0x100000042
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 17
numChildren = 0
[zk: localhost:2181(CONNECTED) 3]
可以看到现在rm1成为master,高可用配置成功。