1 Hadoop HA架构详解
1.1 HDFS HA背景
HDFS集群中NameNode 存在单点故障(SPOF)。对于只有一个NameNode的集群,如果NameNode机器出现意外情况,将导致整个集群无法使用,直到NameNode 重新启动。
影响HDFS集群不可用主要包括以下两种情况:一是NameNode机器宕机,将导致集群不可用,重启NameNode之后才可使用;二是计划内的NameNode节点软件或硬件升级,导致集群在短时间内不可用。
为了解决上述问题,Hadoop给出了HDFS的高可用HA方案:HDFS通常由两个NameNode组成,一个处于active状态,另一个处于standby状态。Active NameNode对外提供服务,比如处理来自客户端的RPC请求,而Standby NameNode则不对外提供服务,仅同步Active NameNode的状态,以便能够在它失败时快速进行切换。
1.2 HDFS HA架构
一个典型的HA集群,NameNode会被配置在两台独立的机器上,在任何时间上,一个NameNode处于活动状态,而另一个NameNode处于备份状态,活动状态的NameNode会响应集群中所有的客户端,备份状态的NameNode只是作为一个副本,保证在必要的时候提供一个快速的转移。
为了让Standby Node与Active Node保持同步,这两个Node都与一组称为JNS的互相独立的进程保持通信(Journal Nodes)。当Active Node上更新了namespace,它将记录修改日志发送给JNS的多数派。Standby noes将会从JNS中读取这些edits,并持续关注它们对日志的变更。Standby Node将日志变更应用在自己的namespace中,当failover发生时,Standby将会在提升自己为Active之前,确保能够从JNS中读取所有的edits,即在failover发生之前Standy持有的namespace应该与Active保持完全同步。
为了支持快速failover,Standby node持有集群中blocks的最新位置是非常必要的。为了达到这一目的,DataNodes上需要同时配置这两个Namenode的地址,同时和它们都建立心跳链接,并把block位置发送给它们。
任何时刻,只有一个Active NameNode是非常重要的,否则将会导致集群操作的混乱,那么两个NameNode将会分别有两种不同的数据状态,可能会导致数据丢失,或者状态异常,这种情况通常称为“split-brain”(脑裂,三节点通讯阻断,即集群中不同的Datanodes却看到了两个Active NameNodes)。对于JNS而言,任何时候只允许一个NameNode作为writer;在failover期间,原来的Standby Node将会接管Active的所有职能,并负责向JNS写入日志记录,这就阻止了其他NameNode基于处于Active状态的问题。
基于QJM的HDFS HA方案如上图所示,其处理流程为:集群启动后一个NameNode处于Active状态,并提供服务,处理客户端和DataNode的请求,并把editlog写到本地和share editlog(这里是QJM)中。另外一个NameNode处于Standby状态,它启动的时候加载fsimage,然后周期性的从share editlog中获取editlog,保持与Active节点的状态同步。为了实现Standby在Active挂掉后迅速提供服务,需要DataNode同时向两个NameNode汇报,使得Stadnby保存block to DataNode信息,因为NameNode启动中最费时的工作是处理所有DataNode的blockreport。为了实现热备,增加FailoverController和Zookeeper,FailoverController与Zookeeper通信,通过Zookeeper选举机制,FailoverController通过RPC让NameNode转换为Active或Standby。
1.3 HDFS HA配置要素
NameNode机器:两台配置对等的物理机器,它们分别运行Active和Standby Node。
JouralNode机器:运行JouralNodes的机器。JouralNode守护进程相当的轻量级,可以和Hadoop的其他进程部署在一起,比如NameNode、DataNode、ResourceManager等,至少需要3个且为奇数,如果你运行了N个JNS,那么它可以允许(N-1)/2个JNS进程失效并且不影响工作。
在HA集群中,Standby NameNode还会对namespace进行checkpoint操作(继承Backup Namenode的特性),因此不需要在HA集群中运行SecondaryNameNode、CheckpointNode或者BackupNode。
1.4 HDFS HA配置参数
需要在hdfs.xml中配置如下参数:
dfs.nameservices:HDFS NN的逻辑名称,例如myhdfs。
dfs.ha.namenodes.myhdfs:给定服务逻辑名称myhdfs的节点列表,如nn1、nn2。
dfs.namenode.rpc-address.myhdfs.nn1:myhdfs中nn1对外服务的RPC地址。
dfs.namenode.http-address.myhdfs.nn1:myhdfs中nn1对外服务http地址。
dfs.namenode.shared.edits.dir:JournalNode的服务地址。
dfs.journalnode.edits.dir:JournalNode在本地磁盘存放数据的位置。
dfs.ha.automatic-failover.enabled:是否开启NameNode失败自动切换。
dfs.ha.fencing.methods :配置隔离机制,通常为sshfence。
1.5 HDFS自动故障转移
HDFS的自动故障转移主要由Zookeeper和ZKFC两个组件组成。
Zookeeper集群作用主要有:一是故障监控。每个NameNode将会和Zookeeper建立一个持久session,如果NameNode失效,那么此session将会过期失效,此后Zookeeper将会通知另一个Namenode,然后触发Failover;二是NameNode选举。ZooKeeper提供了简单的机制来实现Acitve Node选举,如果当前Active失效,Standby将会获取一个特定的排他锁,那么获取锁的Node接下来将会成为Active。
ZKFC是一个Zookeeper的客户端,它主要用来监测和管理NameNodes的状态,每个NameNode机器上都会运行一个ZKFC程序,它的职责主要有:一是健康监控。ZKFC间歇性的ping NameNode,得到NameNode返回状态,如果NameNode失效或者不健康,那么ZKFS将会标记其为不健康;二是Zookeeper会话管理。当本地NaneNode运行良好时,ZKFC将会持有一个Zookeeper session,如果本地NameNode为Active,它同时也持有一个“排他锁”znode,如果session过期,那么次lock所对应的znode也将被删除;三是选举。当集群中其中一个NameNode宕机,Zookeeper会自动将另一个激活。
1.6 YARN HA架构
YARN的HA架构和HDFSHA类似,需要启动两个ResourceManager,这两个ResourceManager会向ZooKeeper集群注册,通过ZooKeeper管理它们的状态(Active或Standby)并进行自动故障转移。
2 高可用集群规划
1.集群规划:
IP 安装的软件
drguo1 192.168.80.149 jdk、hadoop NameNode、DFSZKFailoverController(zkfc)、ResourceManager
drguo2 192.168.80.150 jdk、hadoop NameNode、DFSZKFailoverController(zkfc)、ResourceManager
drguo3 192.168.80.151 jdk、hadoop、zookeeper DataNode、NodeManager、JournalNode、QuorumPeerMain
drguo4 192.168.80.152 jdk、hadoop、zookeeper DataNode、NodeManager、JournalNode、QuorumPeerMain
drguo5192.168.80.153jdk、hadoop、zookeeper
排的好好的,显示出来就乱了!!!
2.前期准备:
准备五台机器,修改静态IP、主机名、主机名与IP的映射,关闭防火墙,安装JDK并配置环境变量(不会请看这),创建用户:用户组,SSH免密码登录SSH免密码登录(报错请看这)。
注意:要把127.0.1.1那一行注释掉,要不然会出现jps显示有datanode,但网页显示live nodes为0;
注释之后就正常了,好像有人没注释也正常,我也不知道为什么0.0
3.搭建zookeeper集群(drguo3/drguo4/drguo5)
见:ZooKeeper完全分布式集群搭建
4.正式开始搭建Hadoop HA集群
去官网下最新的Hadoop(http://apache.opencas.org/hadoop/common/stable/),目前最新的是2.7.2,下载完之后把它放到/opt/Hadoop下
[plain] view plain copy
1. guo@guo:~/下载$ mv ./hadoop-2.7.2.tar.gz /opt/Hadoop/
2. mv: 无法创建普通文件"/opt/Hadoop/hadoop-2.7.2.tar.gz": 权限不够
3. guo@guo:~/下载$ su root
4. 密码:
5. root@guo:/home/guo/下载# mv ./hadoop-2.7.2.tar.gz /opt/Hadoop/
解压
[plain] view plain copy
1. guo@guo:/opt/Hadoop$ sudo tar -zxf hadoop-2.7.2.tar.gz
2. [sudo] guo 的密码:
解压jdk的时候我用的是tar -zxvf,其中的v呢就是看一下解压的过程,不想看你可以不写。
修改opt目录所有者(用户:用户组)直接把opt目录的所有者/组换成了guo。具体情况在ZooKeeper完全分布式集群搭建说过。
[plain] view plain copy
1. root@guo:/opt/Hadoop# chown -R guo:guo /opt
设置环境变量
[plain] view plain copy
1. guo@guo:/opt/Hadoop$ sudo gedit /etc/profile
在最后加上(这样设置在执行bin/sbin目录下的脚本时就不用进入该目录用了)
[plain] view plain copy
1. #hadoop
2. export HADOOP_HOME=/opt/Hadoop/hadoop-2.7.2
3. export PATH=$PATH:$HADOOP_HOME/sbin
4. export PATH=$PATH:$HADOOP_HOME/bin
然后更新配置
[plain] view plain copy
1. guo@guo:/opt/Hadoop$ source /etc/profile
修改/opt/Hadoop/hadoop-2.7.2/etc/hadoop下的hadoop-env.sh
[plain] view plain copy
1. guo@guo:/opt/Hadoop$ cd hadoop-2.7.2
2. guo@guo:/opt/Hadoop/hadoop-2.7.2$ cd etc/hadoop/
3. guo@guo:/opt/Hadoop/hadoop-2.7.2/etc/hadoop$ sudo gedit ./hadoop-env.sh
进入文件后
[plain] view plain copy
1. export JAVA_HOME=${JAVA_HOME}#将这个改成JDK路径,如下
2. export JAVA_HOME=/opt/Java/jdk1.8.0_73
然后更新文件配置
[plain] view plain copy
1. guo@guo:/opt/Hadoop/hadoop-2.7.2/etc/hadoop$ source ./hadoop-env.sh
前面配置和单机模式一样,我就直接复制了。
注意:汉语注释是给你看的,复制粘贴的时候都删了!!!
修改core-site.xml
[html] view plain copy
1. <configuration>
2. <!-- 指定hdfs的nameservice为ns1 -->
3. <property>
4. <name>fs.defaultFS</name>
5. <value>hdfs://ns1/</value>
6. </property>
7. <!-- 指定hadoop临时目录 -->
8. <property>
9. <name>hadoop.tmp.dir</name>
10. <value>/opt/Hadoop/hadoop-2.7.2/tmp</value>
11. </property>
12. <!-- 指定zookeeper地址 -->
13. <property>
14. <name>ha.zookeeper.quorum</name>
15. <value>drguo3:2181,drguo4:2181,drguo5:2181</value>
16. </property>
17. </configuration>
修改hdfs-site.xml
[html] view plain copy
1. <configuration>
2. <!--指定hdfs的nameservice为ns1,需要和core-site.xml中的保持一致 -->
3. <property>
4. <name>dfs.nameservices</name>
5. <value>ns1</value>
6. </property>
7. <!-- ns1下面有两个NameNode,分别是nn1,nn2 -->
8. <property>
9. <name>dfs.ha.namenodes.ns1</name>
10. <value>nn1,nn2</value>
11. </property>
12. <!-- nn1的RPC通信地址 -->
13. <property>
14. <name>dfs.namenode.rpc-address.ns1.nn1</name>
15. <value>drguo1:9000</value>
16. </property>
17. <!-- nn1的http通信地址 -->
18. <property>
19. <name>dfs.namenode.http-address.ns1.nn1</name>
20. <value>drguo1:50070</value>
21. </property>
22. <!-- nn2的RPC通信地址 -->
23. <property>
24. <name>dfs.namenode.rpc-address.ns1.nn2</name>
25. <value>drguo2:9000</value>
26. </property>
27. <!-- nn2的http通信地址 -->
28. <property>
29. <name>dfs.namenode.http-address.ns1.nn2</name>
30. <value>drguo2:50070</value>
31. </property>
32. <!-- 指定NameNode的元数据在JournalNode上的存放位置 -->
33. <property>
34. <name>dfs.namenode.shared.edits.dir</name>
35. <value>qjournal://drguo3:8485;drguo4:8485;drguo5:8485/ns1</value>
36. </property>
37. <!-- 指定JournalNode在本地磁盘存放数据的位置 -->
38. <property>
39. <name>dfs.journalnode.edits.dir</name>
40. <value>/opt/Hadoop/hadoop-2.7.2/journaldata</value>
41. </property>
42. <!-- 开启NameNode失败自动切换 -->
43. <property>
44. <name>dfs.ha.automatic-failover.enabled</name>
45. <value>true</value>
46. </property>
47. <!-- 配置失败自动切换实现方式 -->
48. <property>
49. <name>dfs.client.failover.proxy.provider.ns1</name>
50. <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
51. </property>
52. <!-- 配置隔离机制方法,多个机制用换行分割,即每个机制暂用一行-->
53. <property>
54. <name>dfs.ha.fencing.methods</name>
55. <value>
56. sshfence
57. shell(/bin/true)
58. </value>
59. </property>
60. <!-- 使用sshfence隔离机制时需要ssh免登陆 -->
61. <property>
62. <name>dfs.ha.fencing.ssh.private-key-files</name>
63. <value>/home/guo/.ssh/id_rsa</value>
64. </property>
65. <!-- 配置sshfence隔离机制超时时间 -->
66. <property>
67. <name>dfs.ha.fencing.ssh.connect-timeout</name>
68. <value>30000</value>
69. </property>
70. </configuration>
先将mapred-site.xml.template改名为mapred-site.xml然后修改mapred-site.xml
[html] view plain copy
- <configuration>
- <!-- 指定mr框架为yarn方式 -->
- <property>
- <name>mapreduce.framework.name</name>
- <value>yarn</value>
- </property>
- </configuration>
修改yarn-site.xml
[html] view plain copy
1. <configuration>
2. <!-- 开启RM高可用 -->
3. <property>
4. <name>yarn.resourcemanager.ha.enabled</name>
5. <value>true</value>
6. </property>
7. <!-- 指定RM的cluster id -->
8. <property>
9. <name>yarn.resourcemanager.cluster-id</name>
10. <value>yrc</value>
11. </property>
12. <!-- 指定RM的名字 -->
13. <property>
14. <name>yarn.resourcemanager.ha.rm-ids</name>
15. <value>rm1,rm2</value>
16. </property>
17. <!-- 分别指定RM的地址 -->
18. <property>
19. <name>yarn.resourcemanager.hostname.rm1</name>
20. <value>drguo1</value>
21. </property>
22. <property>
23. <name>yarn.resourcemanager.hostname.rm2</name>
24. <value>drguo2</value>
25. </property>
26. <!-- 指定zk集群地址 -->
27. <property>
28. <name>yarn.resourcemanager.zk-address</name>
29. <value>drguo3:2181,drguo4:2181,drguo5:2181</value>
30. </property>
31. <property>
32. <name>yarn.nodemanager.aux-services</name>
33. <value>mapreduce_shuffle</value>
34. </property>
35. </configuration>
修改slaves
[html] view plain copy
1. drguo3
2. drguo4
3. drguo5
把Hadoop整个目录拷贝到drguo2/3/4/5,拷之前把share下doc删了(文档不用拷),这样会快点。
5.启动zookeeper集群(分别在drguo3、drguo4、drguo5上启动zookeeper)
[plain] view plain copy
1. guo@drguo3:~$ zkServer.sh start
2. ZooKeeper JMX enabled by default
3. Using config: /opt/zookeeper-3.4.8/bin/../conf/zoo.cfg
4. Starting zookeeper ... STARTED
5. guo@drguo3:~$ jps
6. 2005 Jps
7. 1994 QuorumPeerMain
8. guo@drguo3:~$ ssh drguo4
9. Welcome to Ubuntu 15.10 (GNU/Linux 4.2.0-16-generic x86_64)
10.
11. * Documentation: https://help.ubuntu.com/
12.
13. Last login: Fri Mar 25 14:04:43 2016 from 192.168.80.151
14. guo@drguo4:~$ zkServer.sh start
15. ZooKeeper JMX enabled by default
16. Using config: /opt/zookeeper-3.4.8/bin/../conf/zoo.cfg
17. Starting zookeeper ... STARTED
18. guo@drguo4:~$ jps
19. 1977 Jps
20. 1966 QuorumPeerMain
21. guo@drguo4:~$ exit
22. 注销
23. Connection to drguo4 closed.
24. guo@drguo3:~$ ssh drguo5
25. Welcome to Ubuntu 15.10 (GNU/Linux 4.2.0-16-generic x86_64)
26.
27. * Documentation: https://help.ubuntu.com/
28.
29. Last login: Fri Mar 25 14:04:56 2016 from 192.168.80.151
30. guo@drguo5:~$ zkServer.sh start
31. ZooKeeper JMX enabled by default
32. Using config: /opt/zookeeper-3.4.8/bin/../conf/zoo.cfg
33. Starting zookeeper ... STARTED
34. guo@drguo5:~$ jps
35. 2041 Jps
36. 2030 QuorumPeerMain
37. guo@drguo5:~$ exit
38. 注销
39. Connection to drguo5 closed.
40. guo@drguo3:~$ zkServer.sh status
41. ZooKeeper JMX enabled by default
42. Using config: /opt/zookeeper-3.4.8/bin/../conf/zoo.cfg
43. Mode: leader
6.启动journalnode(分别在drguo3、drguo4、drguo5上启动journalnode)注意只有第一次需要这么启动,之后启动hdfs会包含journalnode。
[plain] view plain copy
1. guo@drguo3:~$ hadoop-daemon.sh start journalnode
2. starting journalnode, logging to /opt/Hadoop/hadoop-2.7.2/logs/hadoop-guo-journalnode-drguo3.out
3. guo@drguo3:~$ jps
4. 2052 Jps
5. 2020 JournalNode
6. 1963 QuorumPeerMain
7. guo@drguo3:~$ ssh drguo4
8. Welcome to Ubuntu 15.10 (GNU/Linux 4.2.0-16-generic x86_64)
9.
10. * Documentation: https://help.ubuntu.com/
11.
12. Last login: Fri Mar 25 00:09:08 2016 from 192.168.80.149
13. guo@drguo4:~$ hadoop-daemon.sh start journalnode
14. starting journalnode, logging to /opt/Hadoop/hadoop-2.7.2/logs/hadoop-guo-journalnode-drguo4.out
15. guo@drguo4:~$ jps
16. 2103 Jps
17. 2071 JournalNode
18. 1928 QuorumPeerMain
19. guo@drguo4:~$ exit
20. 注销
21. Connection to drguo4 closed.
22. guo@drguo3:~$ ssh drguo5
23. Welcome to Ubuntu 15.10 (GNU/Linux 4.2.0-16-generic x86_64)
24.
25. * Documentation: https://help.ubuntu.com/
26.
27. Last login: Thu Mar 24 23:52:17 2016 from 192.168.80.152
28. guo@drguo5:~$ hadoop-daemon.sh start journalnode
29. starting journalnode, logging to /opt/Hadoop/hadoop-2.7.2/logs/hadoop-guo-journalnode-drguo5.out
30. guo@drguo5:~$ jps
31. 2276 JournalNode
32. 2308 Jps
33. 1959 QuorumPeerMain
34. guo@drguo5:~$ exit
35. 注销
36. Connection to drguo5 closed.
在drguo4/5启动时发现了问题,没有journalnode,查看日志发现是因为汉语注释造成的,drguo4/5全删了问题解决。drguo4/5的拼音输入法也不能用,我很蛋疼。。镜像都是复制的,咋还变异了呢。
7.格式化HDFS(在drguo1上执行)
[plain] view plain copy
1. guo@drguo1:/opt$ hdfs namenode -format
这回又出问题了,还是汉语注释闹得,drguo1/2/3也全删了,问题解决。
注意:格式化之后需要把tmp目录拷给drguo2(不然drguo2的namenode起不来)
[plain] view plain copy
1. guo@drguo1:/opt/Hadoop/hadoop-2.7.2$ scp -r tmp/ drguo2:/opt/Hadoop/hadoop-2.7.2/
8.格式化ZKFC(在drguo1上执行)
[plain] view plain copy
1. guo@drguo1:/opt$ hdfs zkfc -formatZK
9.启动HDFS(在drguo1上执行)
[plain] view plain copy
1. guo@drguo1:/opt$ start-dfs.sh
10.启动YARN(在drguo1上执行)
[plain] view plain copy
1. guo@drguo1:/opt$ start-yarn.sh
PS:
1.drguo2的resourcemanager需要手动单独启动:
yarn-daemon.sh start resourcemanager
2.namenode、datanode也可以单独启动:
hadoop-daemon.sh start namenode
hadoop-daemon.sh start datanode
3.NN 由standby转化成active
hdfs haadmin -transitionToActive nn1 --forcemanual
大功告成!!!