HDFS HA版搭建
- 简述
- 1.环境搭建
简述
在非HA中,节点组成分别由NN,SNN,DN组成,而其中的负责元数据管理的大管家namenode是单机架构部署的,当一台宕机后,元数据都将会无法访问,造成服务的不可用。因此如何保证HDFS的服务高可用是一个十分重要的问题。
HDFS高可用的解决方案可以用下图概括:
该方案中,namenode升级为两台主备模式(所谓主备,就是只有一台对外服务(active状态)),另外一台不提供服务(standby状态),随时准备替补,当一台挂掉后,另一台此时会立即唤起提供服务)部署,可以显著提高服务的可用性,此时的SNN不再进行合并日志的服务,因为备机不提供服务,可以去进行合并日志的操作,但多集群部署随之而来的问题就是信息的“一致性”。
注:两个NN我们后面分别称呼为N1,N2
在HDFS中,NN中的信息来源大致有两种:1.来自DN的心跳确认同步信息。2.来自client端的请求造成的元数据信息。
对于1的信息,我们可以让DN同时向每一个NN发送消息就可以了。但是2的来自client的信息,加入client端一会向N1发送,一会向N2发送,
那该如何解决这种问题呢?
我们顺着思路,可以不难想到两种方法:
1.同步阻塞:client端向N1发送一个操作信息的时候,N1接到后再向N2发送,N2如果接受到了,就返回一个OK,最终返回给客户端。
2.异步非阻塞:client端向N1发送一个操作信息,N1接到信息后向N2发送,然后N1直接返回客户端OK。
但是这两种都是有问题的:
1方法中,如果N1成功接受到了消息,但到了N2失败了,返回给客户端是失败的响应,但其实N1已经接受到信息了,这就造成了不可用的问题。
2方法中,N1接受到了,发送给N2,如果此时N2因为某些原因宕机,处理失败了,这就又还是造成了信息不一致的情况。
因此考虑到这些,最后可以想到一个折中的方法,我们在两台NN之间建立一个中间件JNN,用于存储这些信息,N1直接发送到这个中间件JNN中去。N2即使宕机了,在之后恢复过来之后,还是可以去这个中间件JNN当中去取得这个数据,可以达到最终一致性的效果,这样,可用性和一致性就都有了。
但这个中间件是不是也存在可用性的问题呢? 如果这个中间件宕机了,是不是可用性的问题又出现了。因此还需要将这个中间件JNN进行集群主从(访问主机时可以进行查询和修改,访问从机时可以进行查询,但进行的修改会转发到主机进行处理)部署。但此时刚刚的问题就又出现了,多个集群中间件节点如何保证数据的一致性和可用性呢? 是不是感觉像是陷入了一个死循环了。
这时候,一种比较完美的解决方法就出来了:使用一种过半成功的Paxos选举算法,举个例子,在班里,老师让大家选出班里最帅的人来进行投票,可能不乏有些自信到不行的投给了自己,但如果并非事实,最终他的票数可能只是他自己投给了自己,最高的那个,往往就是事实上确实如此的人。
换做我们这里,也就是说假如有3个中间件节点,只要有>=一半的节点是返回成功的,那我们就可以认为本次消息是存储成功的。
至此,我们终于算是达成了最终一致性+可用性的实现。
此时大致上我们的高可用算是完成了,但两个NN当active的“主”挂掉后,需要将两者的状态切换还处于一个需要人工手动去切换的样子,因此我们还差将它们可以进行自动化切换。。 此时,我们可以借助zookeeper来对我们的NN主备的状态进行协调管理。zookeeper内部是通过创建目录锁的一种机制,来确定主的,也就是谁在当前时刻是active的。
同时zookeeper通过在每个NN的机器上放置一个zkfc(DFSZKFailoverController)进行监控当前机器NN的状态,在必要的时刻进行对状态的切换。
可以有3种情况:
1.当NN挂掉时,zkfc会通知将zookeeper中的目录锁释放掉,同时通知另外一个处于standby的zkfc,另外一个zkfc接到通知后,会拿到目录锁,并会去检查挂掉的NN是否真的挂掉了,如果真的挂掉了,则将自己机器这边的NN进行升级为active。
2.当zkfc挂掉了,锁也会自动释放掉,同时通知另外一个处于standby的zkfc,另外一个zkfc接到通知后,会拿到目录锁,并会去将挂掉方的NN降级为standby,将自己机器这边的NN进行升级为active。
3.如果因为某种原因,自己机器的zkfc和NN互相连接没问题,但跟外接无法建立连接(例如网卡故障),这时,锁也会自动释放掉,同时通知另外一个处于standby的zkfc,另外一个zkfc接到通知后,会拿到目录锁,会照旧去尝试连接一下挂掉放的NN,但此时发现连接不上,于是会一直重试,一直重试,也不会将自身的NN升级为active,直到能获取到另一方的NN为止。
1.环境搭建
在已搭建好4台虚拟机节点的基础上,进行环境搭建。
采用图示的节点分布位置进行搭建。
NN分别搭建在node01和node02
JNN分别搭建在node1,node02,node03
DN分别搭建在node02,node03,node04
zkfc分别搭建在node01和node02
zk服务三个节点分别搭建在node02,node03,node04
配置:
core-site.xml
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>node02:2181,node03:2181,node04:2181</value>
</property>
hdfs-site.xml
#以下是 一对多,逻辑到物理节点的映射
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>node01:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>node02:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>node01:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>node02:50070</value>
</property>
#以下是JN在哪里启动,数据存那个磁盘
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node01:8485;node02:8485;node03:8485/mycluster</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/var/bigdata/hadoop/ha/dfs/jn</value>
</property>
#HA角色切换的代理类和实现方法,我们用的ssh免密
<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_dsa</value>
</property>
#开启自动化: 启动zkfc
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
流程:
基础设施
ssh免密:
1)启动start-dfs.sh脚本的机器需要将公钥分发给别的节点
2)在HA模式下,每一个NN身边会启动ZKFC,
ZKFC会用免密的方式控制自己和其他NN节点的NN状态
应用搭建
HA 依赖 ZK 搭建ZK集群
修改hadoop的配置文件,并集群同步
初始化启动
1)先启动JN hadoop-daemon.sh start journalnode
2)选择一个NN 做格式化:hdfs namenode -format <只有第一次搭建做,以后不用做>
3)启动这个格式化的NN ,以备另外一台同步 hadoop-daemon.sh start namenode
4)在另外一台机器中: hdfs namenode -bootstrapStandby
5)格式化zk: hdfs zkfc -formatZK <只有第一次搭建做,以后不用做>
6) start-dfs.sh
实操
1)停止之前的集群
2)免密:node01,node02
node02:
cd ~/.ssh
ssh-keygen -t dsa -P '' -f ./id_dsa
cat id_dsa.pub >> authorized_keys
scp ./id_dsa.pub node01:`pwd`/node02.pub
node01:
cd ~/.ssh
cat node02.pub >> authorized_keys
3)zookeeper 集群搭建 java语言开发 需要jdk 部署在2,3,4
node02:
tar xf zook....tar.gz
mv zoo... /opt/bigdata
cd /opt/bigdata/zoo....
cd conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
datadir=/var/bigdata/hadoop/zk
server.1=node02:2888:3888
server.2=node03:2888:3888
server.3=node04:2888:3888
mkdir /var/bigdata/hadoop/zk
echo 1 > /var/bigdata/hadoop/zk/myid
vi /etc/profile
export ZOOKEEPER_HOME=/opt/bigdata/zookeeper-3.4.6
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$ZOOKEEPER_HOME/bin
. /etc/profile
cd /opt/bigdata
scp -r ./zookeeper-3.4.6 node03:`pwd`
scp -r ./zookeeper-3.4.6 node04:`pwd`
node03:
mkdir /var/bigdata/hadoop/zk
echo 2 > /var/bigdata/hadoop/zk/myid
*环境变量
. /etc/profile
node04:
mkdir /var/bigdata/hadoop/zk
echo 3 > /var/bigdata/hadoop/zk/myid
*环境变量
. /etc/profile
node02~node04:
zkServer.sh start
4)配置hadoop的core和hdfs
5)分发配置
给每一台都分发
6)初始化:
1)先启动JN hadoop-daemon.sh start journalnode
2)选择一个NN 做格式化:hdfs namenode -format <只有第一次搭建做,以后不用做>
3)启动这个格式化的NN ,以备另外一台同步 hadoop-daemon.sh start namenode
4)在另外一台机器中: hdfs namenode -bootstrapStandby
5)格式化zk: hdfs zkfc -formatZK <只有第一次搭建做,以后不用做>
6) start-dfs.sh