影响HDFS集群不可用主要包括以下两种情况:
一是NameNode机器宕机,将导致集群不可用,重启NameNode之后才可使用;
二是计划内的NameNode节点软件或硬件升级,导致集群在短时间内不可用。
为了解决上述问题,Hadoop给出了HDFS的高可用HA方案: HDFS通常由两个NameNode组成,一个处于active状态,另一个处于standby状态。Active NameNode对外提供服务,比如处理来自客户端的RPC请求,而Standby NameNode则不对外提供服务,仅同步Active NameNode的状态,以便能够在它失败时快速进行切换。
在典型的 HA 集群中,通常有两台不同的机器充当 NN(namenode)。在任何时间,只有一台机器处于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;事实上,运行这些守护进程是错误的。
实验环境:
rhel7.3 firewalld is disabled 主机名(IP)服务server1(172.25.254.1)namenode,hdfs,nfsserver2(172.25.254.2)zookeeper(journalnode)hdfs,nfsserver3(172.25.254.3)zookeeper(journalnode)hdfs,nfsserver4(172.25.254.4)zookeeper(journalnode),hdfs,nfsserver5(172.25.254.5)备namenode,hdfs,nfsZookeeper:JournalNode machines(server2,server3,server4)的配置
1.在server1上关闭之前部书的hdfs服务
[hadoop@server1 hadoop]$ sbin/stop-dfs.sh Stopping namenodes on [server1] Stopping datanodes Stopping secondary namenodes [server1] [hadoop@server1 hadoop]$ jps 2500 Jps //关闭yarn组吉安的配置 [hadoop@server1 hadoop]$ sbin/stop-yarn.sh //如果对hadoop进行了相应的运算需要在/tmp中将运算产生的数据信息进行清除2.在server2上搭建zoopkeeper,并且编辑配置文件添加从节点信息
[hadoop@server2 ~]$ tar zxf zookeeper-3.4.9.tar.gz [hadoop@server2 ~]$ cd zookeeper-3.4.9 [hadoop@server2 zookeeper-3.4.9]$ cd conf/ [hadoop@server2 conf]$ cp zoo_sample.cfg zoo.cfg [hadoop@server2 conf]$ vim zoo.cfg 文件编辑内容如下://添加三个节点的相应信息 tickTime=2000 initLimit=10 syncLimit=5 dataDir=/tmp/zookeeper //myid的存放路径 clientPort=2181 server.1=172.25.254.2:2888:3888 server.2=172.25.254.3:2888:3888 server.3=172.25.254.4:2888:3888配置文件参数详解:
clientPort:客户端连接 server 的端口,即对外服务端口,一般设置为 2181dataDir:存储快照文件 snapshot 的目录。默认情况下,事务日志也会存储在这里。建议同时配置参 数 dataLogDir, 事务日志的写性能直接影响 zk 性能tickTime:ZK 中的一个时间单元。ZK 中所有时间都是以这个时间单元为基础,以毫秒计,用来调节心跳和超时。例如,session 的最小超时时间是 2*tickTime。dataLogDir:事务日志输出目录。尽量给事务日志的输出配置单独的磁盘或是挂载点,这将极大的提升ZK 性能globalOutstandingLimit:最大请求堆积数。默认是 1000。ZK 运行的时候, 尽管server 已经没有空闲来处理更多的客户端请求了,但是还是允许客户端将请求提交到服务器上来,以提高吞吐性能。当然,为了防止Server 内存溢出,这个请求堆积数还是需要限制下的。initLimit:Follower 在启动过程中,会从 Leader 同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader 允许 F 在 initLimit 时间内完成这个工作。通常情况下,我们不用太在意这个参数的设置。如果 ZK 集群的数据量确实很大了,F 在启动的时候,从 Leader 上同步数据的时间也会相应变长,因此在这种情况下,有必要适当调大这个参数了syncLimit:在运行过程中,Leader 负责与 ZK 集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。如果 L 发出心跳包在 syncLimit 之后,还没有从 F 那里收到响应,那么就认为这个 F 已经不在线了。注意:不要把这个参数设置得过大,否则可能会掩盖一些问题3.添加的3个节点配置文件相同,并且需要在/tmp/zookeeper 目录中创建 myid 文件,写入一个唯一的数字,取值范围在 1-255。此数字与配置文件中的定义保持一致,(server.1=172.25.0.2:2888:3888),其它节点依次类推。
//server2节点: [hadoop@server2 conf]$ mkdir /tmp/zookeeper [hadoop@server2 conf]$ echo 1 > /tmp/zookeeper/myid //server3节点: [hadoop@server3 conf]$ mkdir /tmp/zookeeper [hadoop@server3 conf]$ echo 2 > /tmp/zookeeper/myid //server4节点: [hadoop@server4 conf]$ mkdir /tmp/zookeeper [hadoop@server4 conf]$ echo 3 > /tmp/zookeeper/myid4.在三个节点开启服务并且查看状态
//server2: [hadoop@server2 zookeeper-3.4.9]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [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 Error contacting service. It is probably not running. [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 ##显示为从 //server3: [hadoop@server3 ~]$ cd zookeeper-3.4.9 [hadoop@server3 zookeeper-3.4.9]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [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: leader ##显示为主 //server4上: [hadoop@server4 zookeeper-3.4.9]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [hadoop@server4 zookeeper-3.4.9]$ bin/zkServer.sh stztus ZooKeeper JMX enabled by default Using config: /home/hadoop/zookeeper-3.4.9/bin/../conf/zoo.cfg Usage: bin/zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd} [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: follower ##显示为从5.在任意一个节点登陆zookeeper查看
[hadoop@server2 bin]$ pwd /home/hadoop/zookeeper-3.4.9/bin [hadoop@server2 bin]$ ./zkCli.sh 连接zookeeper [zk: localhost:2181(CONNECTED) 0] ls / [zookeeper] [zk: localhost:2181(CONNECTED) 1] ls /zookeeper [quota] [zk: localhost:2181(CONNECTED) 2] ls /zookeeper/quota ##没有添加zookeeper的相应信息,所以没有相应内容hadoop(server1,server5)的配置
1.编辑配置文件添加相应信息
[hadoop@server1 ~]$ cd /home/hadoop/hadoop/etc/hadoop/ [hadoop@server1 hadoop]$ vim core-site.xml 文件编辑如下: <configuration> 指定 hdfs 的 namenode 为 masters (名称可自定义) <property> <name>fs.defaultFS</name> <value>hdfs://masters</value> </property> 指定 zookeeper 集群主机地址 <property> <name>ha.zookeeper.quorum</name> <value>172.25.254.2:2181,172.25.254.3:2181,172.25.254.4:2181</value> </property> </configuration> [hadoop@server1 hadoop]$ vim hdfs-site.xml 文件编辑内容如下: <configuration> <property> <name>dfs.replication</name> <value>3</value> </property> <!-- 指定 hdfs 的 nameservices 为 masters,和 core-site.xml 文件中的设置保持一 致 --> <property> <name>dfs.nameservices</name> <value>masters</value> </property> <!-- masters 下面有两个 namenode 节点,分别是 h1 和 h2 (名称可自定义) <property> <name>dfs.ha.namenodes.masters</name> <value>h1,h2</value> </property> <!-- 指定 h1 节点的 rpc 通信地址 --> <property> <name>dfs.namenode.rpc-address.masters.h1</name> <value>172.25.254.1:9000</value> </property> <!-- 指定 h1 节点的 http 通信地址 --> <property> <name>dfs.namenode.http-address.masters.h1</name> <value>172.25.254.1:9870</value> </property> <!-- 指定 h2 节点的 rpc 通信地址 --> <property> <name>dfs.namenode.rpc-address.masters.h2</name> <value>172.25.254.5:9000</value> </property> <!-- 指定 h2 节点的 http 通信地址 --> <property> <name>dfs.namenode.http-address.masters.h2</name> <value>172.25.254.5:9870</value> </property> <!-- 指定 NameNode 元数据在 JournalNode 上的存放位置 --> <property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://172.25.254.2:8485;172.25.254.3:8485;172.25.254.4:8485/masters</value> </property> <!-- 指定 JournalNode 在本地磁盘存放数据的位置 --> <property> <name>dfs.journalnode.edits.dir</name> <value>/tmp/journaldata</value> </property> <!-- 开启 NameNode 失败自动切换 --> <property> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property> <!-- 配置失败自动切换实现方式 --> <property> <name>dfs.client.failover.proxy.provider.masters</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvid er</value> </property> !-- 配置隔离机制方法,每个机制占用一行--> <property> <name>dfs.ha.fencing.methods</name> <value> sshfence shell(/bin/true) </value> </property> <!-- 使用 sshfence 隔离机制时需要 ssh 免密码 --> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/hadoop/.ssh/id_rsa</value> </property> <!-- 配置 sshfence 隔离机制超时时间 --> <property> <name>dfs.ha.fencing.ssh.connect-timeout</name> <value>30000</value> </property> </configuration>启动 hdfs 集群(按顺序启动)
1.启动 hdfs 集群(按顺序启动)在三个 DN 上依次启动 zookeeper 的journalNode节点集群
//server2: [hadoop@server2 hadoop]$ pwd /home/hadoop/hadoop [hadoop@server2 hadoop]$ bin/hdfs --daemon start journalnode [hadoop@server2 hadoop]$ jps 2291 QuorumPeerMain 2539 JournalNode 2557 Jps //server3: [hadoop@server3 hadoop]$ pwd /home/hadoop/hadoop [hadoop@server3 hadoop]$ bin/hdfs --daemon start journalnode [hadoop@server3 hadoop]$ jps 2140 QuorumPeerMain 2300 JournalNode 2318 Jps //server4: [hadoop@server4 hadoop]$ pwd /home/hadoop/hadoop [hadoop@server4 hadoop]$ bin/hdfs --daemon start journalnode [hadoop@server4 hadoop]$ jps 2320 Jps 1534 DataNode 2110 QuorumPeerMain 2302 JournalNode2.格式化 HDFS 集群,传递配置文件搭建高可用Namenode 数据默认存放在/tmp,需要把数据拷贝到 h2
[hadoop@server1 hadoop]$ pwd /home/hadoop/hadoop [hadoop@server1 hadoop]$ bin/hdfs namenode -format ##如果在进行格式化的时候显示/tmp/journaldata数据1节点不为空,可以在server2,server3,server4上删除/tmp/journalnode节点的数据再进行格式化就不会报错了 //在server5上创建数据节点: [root@server5 ~]# useradd hadoop [root@server5 ~]# id hadoop uid=1000(hadoop) gid=1000(hadoop) groups=1000(hadoop) [root@server5 ~]# yum install -y nfs-utils [root@server5 ~]# systemctl start rpcbind [root@server5 ~]# mount 172.25.254.1:/home/hadoop/ /home/hadoop/ [root@server5 ~]# su - hadoop [hadoop@server5 ~]$ cd hadoop [hadoop@server5 hadoop]$ bin/hdfs --daemon start datanode [hadoop@server5 hadoop]$ jps 1690 DataNode 1722 Jps //在server1上: [hadoop@server1 hadoop]$ scp -r /tmp/hadoop-hadoop 172.25.254.5:/tmp VERSION 100% 217 0.2KB/s 00:00 seen_txid 100% 2 0.0KB/s 00:00 fsimage_0000000000000000000.md5 100% 62 0.1KB/s 00:00 fsimage_0000000000000000000 100% 391 0.4KB/s 00:004.格式化 zookeeper (只需在 h1 上执行即可)
[hadoop@server1 hadoop]$ bin/hdfs zkfc -formatZK ##当格式化显示的信息都为info没有error的时候证明格式化没有问题5.启动hdfs集群
[hadoop@server1 hadoop]$ sbin/start-dfs.sh ##在启动服务的时候必须保证其它节点没有datanode进行存在,保证实验环境的纯净 //启动之后分别在server1及server5上查看: 注意在查看时可能出现第一次只出现失败回切域,或者只出现namenode的节点的情况,只需要关掉服务再次启动即可,且server1和server5因为是namnode节点内存需要2G [hadoop@server1 hadoop]$ jps 1431 NameNode 1739 DFSZKFailoverController 2013 Jps [hadoop@server5 ~]$ jps 1191 NameNode 1293 DFSZKFailoverController 1856 Jps //查看journalnode的节点状态: [hadoop@server2 ~]$ jps 1493 JournalNode 1222 QuorumPeerMain 1400 DataNode 1594 Jps [hadoop@server3 ~]$ jps 1578 Jps 1176 QuorumPeerMain 1329 DataNode 1422 JournalNode [hadoop@server4 ~]$ jps 1441 Jps 1153 QuorumPeerMain 1239 DataNode 1332 JournalNodea.查看namenode节点状态: 在同时出现namenode节点及其失败回切域节点则证明集群开启无误。 b.查看journalnode节点状态: 则集群搭建完成
测试:
在浏览器上查看namenode的节点状态:
a.查看server1的namenode的节点状态:为active http://172.25.254.1:9870/ b.查看server5的节点状态:为stundy http://172.25.254.5:9870/ c.用客户端登陆zookeeper登陆查看节点状态
[hadoop@server2 zookeeper-3.4.9]$ pwd /home/hadoop/zookeeper-3.4.9 [hadoop@server2 zookeeper-3.4.9]$ bin/zkCli.sh 查看内容显示如下:d.在active上写入数据并且查看
[hadoop@server1 hadoop]$ bin/hdfs dfs -mkdir /user [hadoop@server1 hadoop]$ bin/hdfs dfs -mkdir /user/hadoop [hadoop@server1 hadoop]$ bin/hdfs dfs -ls [hadoop@server1 hadoop]$ bin/hdfs dfs -put etc/hadoop/ input在浏览器上查看: 可以看到数据上传成功
测试故障自动切换:
1.杀掉 h1 主机的 namenode 进程后依然可以访问,此时 h2 转为 active 状态接管 namenode 在浏览器上查看: 发现备节点变为server5
2.启动 h1 上的 namenode,此时为 standby 状态 在浏览器查看:
1.编辑 mapred-site.xml 文件
[hadoop@server1 hadoop]$ cd /home/hadoop/hadoop/etc/hadoop/ [hadoop@server1 hadoop]$ vim mapred-site.xml 文件编辑内容如下: <configuration> <!-- 指定 yarn 为 MapReduce 的框架 --> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>2.编辑 yarn-site.xml 文件
[hadoop@server1 hadoop]$ pwd /home/hadoop/hadoop/etc/hadoop [hadoop@server1 hadoop]$ vim yarn-site.xml 文件的编辑内容如下: <configuration> <!-- 配置可以在 nodemanager 上运行 mapreduce 程序 --> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <!-- 激活 RM 高可用 --> <property> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <!-- 指定 RM 的集群 id --> <property> <name>yarn.resourcemanager.cluster-id</name> <value>RM_CLUSTER</value> </property> <!-- 定义 RM 的节点--> <property> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2</value> </property> <!-- 指定 RM1 的地址 --> <property> <name>yarn.resourcemanager.hostname.rm1</name> <value>172.25.254.1</value> </property> <!-- 指定 RM2 的地址 --> <property> <name>yarn.resourcemanager.hostname.rm2</name> <value>172.25.254.5</value> </property> <!-- 激活 RM 自动恢复 --> <property> <name>yarn.resourcemanager.recovery.enabled</name> <value>true</value> </property> <!-- 配置 RM 状态信息存储方式,有 MemStore 和 ZKStore--> <property> <name>yarn.resourcemanager.store.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</ value> </property> <!-- 配置为 zookeeper 存储时,指定 zookeeper 集群的地址 --> <property> <name>yarn.resourcemanager.zk-address</name> <value>172.25.254.2:2181,172.25.254.3:2181,172.25.254.4:2181</value> </property> </configuration>3.启动 yarn 服务
//server1:rm1
[hadoop@server1 hadoop]$ cd /home/hadoop/hadoop [hadoop@server1 hadoop]$ sbin/start-yarn.sh [hadoop@server1 hadoop]$ jps 6559 Jps 2163 NameNode 1739 DFSZKFailoverController 5127 ResourceManager//server5:rm2 需要手动启动
[hadoop@server5 hadoop]$ pwd /home/hadoop/hadoop [hadoop@server5 hadoop]$ sbin/yarn-daemon.sh start resourcemanager在zookeeper(journalnode)节点查看: 最好是把 RM 与 NN 分离运行,这样可以更好的保证程序的运行性能。
//在浏览器查看: 4.测试 yarn 故障切换
显示server1为active,在server1上手动kill掉resourcemanager的进程 在浏览器查看server5变为active: 在server1上手动添加resourcemanager并且在浏览器查看变为standby
