本次咱们迎来了《大数据集群环境搭建》的第三篇——HDFS HA篇。HDFS想必你们都不陌生,中文全称是“Hadoop分布式文件系统”(什么,你说中文全称里面为何会有英语单词?反正Hadoop我是不知道怎么翻译)。那么HA是什么呢?HA就是High Availability,中文名“高可用”。那么什么才叫作“高可用”呢,这就要从Hadoop的历史来讲起了。
long long ago,那时候的Hadoop集群中还只有一个NameNode节点。咱们知道,HDFS中全部的文件的元数据是存储在NameNode上的,而真正的文件数据是存储在DataNode上的。DataNode有不少个,而NameNode却只有一个,至关于NameNode是全部Node的“带头大哥”。在频繁而大量的读写操做下,某一个节点挂掉并非什么新鲜事。小弟(DataNode)挂了一个两个的没关系,毕竟只有一部分数据在里面,并且还有冗余备份机制。可是“带头大哥”挂掉了可就不妙了,由于全部数据的元数据全都在大哥那里,大哥一挂掉全部的数据就都无法访问了。这就是集群中很是著名的一个问题——单点故障问题。那么如何避免这个问题呢,曾经有过CheckPoint,BackUp Node等等方案,可是都存在必定问题,最后咱们的HA机制横空出世,一举解决了这个单点故障的问题(啪啪啪,此处应有掌声)。那么HA机制究竟是干了什么呢,简单的来讲,就是在集群中选出一个“二当家”。这时集群中就有了两个NameNode,一个是带头大哥(Active状态),另外一个是“二当家”(Standby状态)。这个“二当家”平时都干什么呢?除了同步“带头大哥”的数据外,全部小弟的状况也都要跟“二当家”汇报(文件块位置信息,心跳包等)。也就是,他一样也存储了全部数据的元数据!这样一来,当“大哥”有个三长两短,“二当家”就能迅速接手原来“大哥”的工做,带领小弟们一如既往的工做(即failover)。这样集群就避免了单点故障问题,实现了“高可用”。目前HDFS只支持两个NameNode的HA机制,但官方的消息是之后可能会推出多个NameNode的HA机制,也就是说在将来,集群中可能出现“三当家”、“四当家”......咱们的集群将会愈来愈健壮。
那么说完了什么是HA,就要说说HDFS如何是如何实现HA的机制的。为了在两个NameNode之间进行数据同步,HDFS支持QJM和NFS。咱们这里主要讲解QJM。
QJM全称是 Quorum Journal Manager,抱歉这个我又不知道怎么翻译。你们只须要理解,当目前处于Active的NameNode发生故障之后,目前处于Standby状态的NameNode会在把本身的状态提高为Active以前,会经过QJM同步全部的以前Active状态的NameNode的数据。具体的原理你们能够自行研究。
那么,对于咱们来说,如何实现HA机制呢?那固然是经过配置文件了。下面我就来和你们一块儿一步一步的把HDFS HA集群搭建起来(整个过程可能略长)。部署HDFS HA以前须要配置服务器和ZooKeeper,不太会配置的同窗们能够参考我以前的文章大数据集群环境搭建——服务器篇和大数据集群环境搭建——ZooKeeper篇。node
软件包你们能够从官网下载本身想要的版本,我这里用到的是2.7.3。接下来解压:shell
tar -xzvf hadoop-2.7.3.tar.gz -C /home/hadoop/deploy
你们能够根据本身实际的目录状况自行调整。apache
建立文件/etc/profile.d/hadoop2.7.3.sh,写入以下环境变量:bootstrap
export HADOOP_HOME=/home/hadoop/deploy/hadoop-2.7.3 export HADOOP_CONF_DIR=/home/hadoop/deploy/hadoop-2.7.3/etc/hadoop
保存并退出,而后以管理员权限执行:segmentfault
source /etc/profile
这个文件在$HADOOP_CONF_DIR中,此文件中配置一个JAVA_HOME便可,注意此处填写绝对路径,若是填写$JAVA_HOME可能会存在问题。其余环境变量请参考官方文档。服务器
这个文件在$HADOOP_CONF_DIR中,本文中配置以下变量,其余变量请参考官方文档。ssh
这里没有使用master1,而是使用了nameservices特性,配置了命名服务mycluster,至于这个nameservices是个什么东西,后面将会说明。分布式
<property> <name>fs.defaultFS</name> <value>hdfs://mycluster:8020</value> </property>
这个变量将用做其余一些须要配置本地文件系统路径的base directory,当这类变量没有显式配置时,将使用这个值做为base directory。ide
<property> <name>hadoop.tmp.dir</name> <value>file:///home/hadoop/bigdata/hadoop_tmp</value> </property>
固然,具体路径仍是要根据实际状况来配置。oop
ZooKeeper会用于两个NameNode的Active节点选举。由于以前配置了五台服务器,因此此处把它们所有写上。
<property> <name>ha.zookeeper.quorum</name> <value>master1,master2,slave1,slave2,slave3</value> </property>
这个文件也是在$HADOOP_CONF_DIR中。
<property> <name>dfs.replication</name> <value>3</value> </property>
<property> <name>dfs.datanode.data.dir</name> <value>file:///home/hadoop/bigdata/hdfs_data_dir</value> </property>
<property> <name>dfs.namenode.name.dir</name> <value>file:///home/hadoop/bigdata/hdfs_name_dir</value> </property>
在但NameNode节点的集群中,对HDFS集群访问的入口是NameNode所在的服务器。可是在两个NameNode节点的HA集群中,没法配置单一服务器入口。因此须要指定一个逻辑上的服务名,这个服务名是自定义的。当外界访问HDFS集群时,入口就变为这个服务。用户没必要关心当前具体是哪台服务器在提供服务(Active状态),只要访问这个服务就能够了。
<property> <name>dfs.nameservices</name> <value>mycluster</value> </property>
此处为两个NameNode的惟一标识,也是能够自定义的。在HDFS集群管理中会用到
<property> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2</value> </property>
<property> <name>dfs.namenode.rpc-address.mycluster.nn1</name> <value>master1:9000</value> </property> <property> <name>dfs.namenode.rpc-address.mycluster.nn2</name> <value>master2:9000</value> </property>
<property> <name>dfs.namenode.http-address.mycluster.nn1</name> <value>master1:50070</value> </property> <property> <name>dfs.namenode.http-address.mycluster.nn2</name> <value>master2:50070</value> </property>
在没有配置HA机制的Hadoop分布式系统中,这个值应该置空。用来进行两个NameNode节点的元数据同步。推荐将nameservice ID做为最后的journal ID。配置的节点将会开启journalnode进程。
<property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://master1:8485;master2:8485;slave1:8485/mycluster</value> </property>
<property> <name>dfs.journalnode.edits.dir</name> <value>/home/hadoop/bigdata/jnode_edits_dir</value> </property>
HDFS客户端用来链接集群中Active状态节点的Java类,ConfiguredFailoverProxyProvider是目前惟一能够指定的类
<property> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property>
这是个值得好好说一下的配置。当配置了HDFS HA集群时,会有两个NameNode,为了不两个NN都为Active状态(这种状况称为split-brain scenario),当发生failover时,Standby的节点要执行一系列方法把原来那个Active节点中不健康的NameNode服务给杀掉(这个过程就称为fence)。而下面这个配置就是配置了执行杀死原来Active NameNode服务的方法。这里面配置的全部方法都会被顺序的执行,最后返回结果即为fence过程的结果。若是fence执行成功,就把原来为Standby的NameNode的状态提高为Active。sshfence方法会经过ssh远程调用fuser命令去找到NameNode服务并杀死它。咱们的目标是当发生failover时,不论如何,就算前面的sshfence执行失败(好比服务器上不存在fuser命令),依然把Standby节点的状态提高为Active,因此最后不管如何要配置一个shell(/bin/true),保证不论前面的方法执行的状况如何,最后fence过程返回的结果都为true。dfs.ha.fencing.ssh.private-key-files配置了ssh命令所须要用到的私钥。
<property> <name>dfs.ha.fencing.methods</name> <value> sshfence shell(/bin/true) </value> </property> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/hadoop/.ssh/id_rsa</value> </property>
由于咱们是要配置自动切换Active状态的集群,因此这项必须为true
<property> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property>
若$HADOOP_CONF_DIR下没有这个文件,请自行建立。指定DataNode节点,每行一个hostname。这样集群中下面配置的每一个节点都将将开启DataNode服务。
slave1 slave2 slave3
当全部配置都完成之后,咱们须要先启动JournalNode服务。在配置了JournalNode服务的每台服务器上执行
hadoop-daemon.sh start journalnode
启动了JournalNode后(能够经过jps命令查看),咱们须要格式化NameNode。在nn1(master1)上执行:
hdfs namenode -format
在另外一台NN服务器nn2(master2)上执行:
hdfs namenode -bootstrapStandby
在每一个JournalNode上执行:
hdfs namenode -initializeSharedEdits
在任意一台NN服务器上执行:
$HADOOP_HOME/bin/hdfs zkfc -formatZK
在任意NN上执行
$HADOOP_HOME/sbin/start-dfs.sh
至此,所有部署完成。访问master1:50070和master2:50070,查看集群状态,两台NN的状态应该为一台Active,另外一台一台Standby。kill掉Active服务器上的NN进程,查看Standby服务器上的NN进程的状态是否变为Active,若是是,则部署成功。若是没有成功,请检查配置是否正确。