【本文转载自:www.bigdata-star.com】
本文整合梳理了主流大数据生态圈中的组件:Hdfs+Yarn+HBase+Spark+Storm的单点故障问题的解决方案:构建HA(High Available)高可用架构。阅读本文之前,最好需要了解清楚各组件的架构原理。
单点故障的出现原因
首先一张图来了解下这些组件的架构:
我们可以发现:它们的共同特点就是都是主从结构。HDFS中的NameNode,Yarn中ResourceManager,Hbase中HMaster,Spark中Master,Storm中Nimbus起着“老大”的角色,那么“老大”挂了怎么办呢?这可就麻烦了,只要老大挂了,等于整个集群的服务都用不了了,NameNode挂了整个集群的HDFS就用不了了,HBase的HMaster挂了整个集群的Hbase都用不了了,等等。这就是所谓的单点故障问题。单点指只有一个主节点。
单点故障的解决方案
既然只有一个主节点就会发生单点故障,那么我们很容易可以想到,我来两个不就行了!对的,HA的思想就是多弄几个主节点,一个死了另一个上。但这样也不够啊!必须有个东西能够使得发生故障的时候自动切换啊!这东西就是Zookeeper。所以有了下面这张图:
由于这些组件的HA原理类似,我们只以最难的HDFS的HA高可用架构原理为例讲解。而其他组件,不讲解原理,只上配置文件。
Zookeeper在HA架构中的作用
Zookeeper是一个开源的分布式协调服务,分布式应用程序可以基于ZooKeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。
ZK在Hadoop生态圈中的主要功能有:
- 选举功能,比如HDFS中Active NameNode的选举、YARN中Active ResourceManager的选举和HBase中Active HMaster的选举。
- ZooKeeper具有在各个节点同步数据的功能,能保证高度的一致性,因此它能够保证在任何时候只有一个节点为Active。
- ZooKeeper分布式协调/通知功能,可用于心跳检测,不同进程之间需要检测到彼此是否在正常运行,比如HDFS中NameNode需要知道DataNode是否正常。基本原理是创建一个临时znode,如果连接超时就删除这个节点,不同的进程直接可以根据这个临时子节点来判断对应的进程是否存活。
HDFS基于Zookeeper的HA高可用架构原理
HDFS预备知识:
namenode职责:
(1)负责客户端的请求和响应
(2)负责元数据的管理(查询,修改。。)
(3)维护元信息(fsimage文件),fsimage是磁盘元数据镜像文件,存储元数据信息。
(4)维护操作日志(edits文件),edits是数据操作日志文件,当客户端操作文件的时候,操作记录首先会被记录到edits日志文件中。
我们可以在$dfs.namenode.name.dir/current目录下看到如下的文件结构
出现HA之后,(3)和(4)交给了另一个叫做JournalNode的东东。JournalNode在HA故障转移中起到了重要的作用!
HDFA HA原理图解
- 在两个NN(NameNode简写,下同)间选举出一个Active NN,Active NN会在ZK上创建临时节点Znode
- 两个NN都会向ZK发送心跳检测信息,让ZK实时知道它们的状态。
- 任何修改操作在 Active NN上执行时,JN进程同时也会记录修改log到至少半数以上的JN中,这时 Standby NN 监测到JN 里面的同步log发生变化了会读取 JN 里面的修改log,然后同步到自己的的目录镜像树里面。
- Active NN挂了之后,连接超时,ZK收不到心跳信息了,就把对应的临时znode进行删除,znode的删除事件会主动触发到下一次的Active NamNode的选择。
- 原来的StandbyNN准备要上位了,它会在成为Active NN 前,读取所有的JN里面的日志,这样就能高可靠的保证与挂掉的NN的目录镜像树一致,然后无缝的接替它的职责,维护来自客户端请求,从而达到一个高可用的目的。
注:故障切换是通过ZKFC(FailOverController)完成。
HDFS的HA高可用架构配置
- core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop-2.6.0-cdh5.11.1/data/tmp</value>
</property>
<property>
<name>hadoop.http.staticuser.user</name>
<value>master</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>master:2181,slave1:2181,slave2:2181</value>
</property>
</configuration>
- hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.http.address</name>
<value>0.0.0.0:50070</value>
</property>
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/usr/local/hadoop-2.6.0-cdh5.11.1/data/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/usr/local/hadoop-2.6.0-cdh5.11.1/data/tmp/dfs/data</value>
</property>
<!-- service name,the same as core-site.xml-->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<!-- RPC address-->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>master:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>slave1:8020</value>
</property>
<!-- http address web service -->
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>master:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>slave1:50070</value>
</property>
<!--journalnode dir -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://master:8485;slave1:8485;slave2:8485/mycluster</value>
</property>
<!--journalnode dir -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/usr/local/hadoop-2.6.0-cdh5.11.1/data/jn</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>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
</configuration>
搭建HDFS HA的步骤
(1)启动zookeeper集群(分别在slave1、slave2和slave3上执行)zkServer.sh start
(2)格式化ZKFC(在master1上执行)hdfs zkfc -formatZK
(3)启动journalnode(分别在slave1、slave2和slave3上执行)sbin/hadoop-daemon.sh start journalnode
(4)格式化HDFS(在master1上执行)hdfs namenode -format
(5)启动nn1sbin/hadoop-daemon.sh start namenode
(6)第二个namenode机器同步元数据信息bin/hdfs namenode -bootstrapStandby
(7)启动nn2sbin/hadoop-daemon.sh start namenode
(6)启动所有datanode sbin/hadoop-daemons.sh start datanode
(7)在master机器上先启动zkfc(自动故障转移) 它就变成active了 sbin/hadoop-daemon.sh start zkfc
(8)再在slave1机器上启动zkfc.它就变成standby了
测试自动故障转移
(1)启动服务
(2)kill命令杀死active nn的进程
(3)在web UI界面上会发现Standby自动变成了Active
Yarn的HA高可用架构
原理与HDFS的非常类似,也是通过Zookeeper心跳检测,自动切换,非常简单,就是配置一下配置文件。
<configuration>
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>rs</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>master</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>slave1</value>
</property>
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>master:2181,slave1:2181,slave2:2181</value>
</property>
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
</configuration>
HBase的HA高可用架构
Hbase其实是无单点故障的,你可以手动启动多个HMaster,比如在master机器上启动hbase(bin/start-hbase.sh
)之后,可以到slave1机器上也启动master(bin/hbase-daemon.sh start master
),无需任何配置。但是手工启动这样有点麻烦,可以通过配置文件,使得每次启动hbase时候自动的帮你启动两个HMaster。touch backup-masters
在此文件上输入你要作为备份HMaster的机器主机名。
Spark的HA高可用架构
Spark同样是用ZooKeeper来实现HA。ZooKeeper提供了一个Leader Election机制,由于ZK的高度一致性,可以保证虽有多个Master但是只有一个是Active的,当Active的Master出现故障时,另外的一个Standby Master会被选举出来。
配置方法
vim conf/spark-env.sh
注释掉原本的SPARK_MASTER_HOST,如果它存在,就会默认只以它为Master。
-Dspark.deploy.recoveryMode: 表明整个集群的恢复和维护都是Zookeeper.
-Dspark.deploy.zookeeper.url: 所有做HA机器,其中端口2181是默认端口。
-Dspark.deploy.zookeeper.dir: 指定Spark在Zookeeper注册的信息
#SPARK_MASTER_HOST=master
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=master:2181,slave1:2181,slave2:2181 -Dspark.deploy.zookeeper.dir=/spark"
需要将它分发给需要做备份Master的机器。
scp conf/spark-env.sh slave1:/usr/local/spark-2.2.0-bin-hadoop2.6.0-cdh5.11.1/conf/
启动方法
在一台机器上:sbin/start-all.sh
另一台机器上启动第二个Master:sbin/start-master.sh