大数据集群环境搭建——HDFS HA篇

2546 查看

本次我们迎来了《大数据集群环境搭建》的第三篇——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篇

1、下载并解压软件包

软件包大家可以从官网下载自己想要的版本,我这里用到的是2.7.3。接下来解压:

tar -xzvf hadoop-2.7.3.tar.gz -C /home/hadoop/deploy

大家可以根据自己实际的目录情况自行调整。

2、配置Hadoop系统环境变量

创建文件/etc/profile.d/hadoop2.7.3.sh,写入如下环境变量:

export HADOOP_HOME=/home/hadoop/deploy/hadoop-2.7.3
export HADOOP_CONF_DIR=/home/hadoop/deploy/hadoop-2.7.3/etc/hadoop

保存并退出,然后以管理员权限执行:

source /etc/profile

3、配置hadoop-env.sh文件

这个文件在$HADOOP_CONF_DIR中,此文件中配置一个JAVA_HOME即可,注意此处填写绝对路径,如果填写$JAVA_HOME可能会存在问题。其他环境变量请参考官方文档。

4、配置core-site.xml文件

这个文件在$HADOOP_CONF_DIR中,本文中配置如下变量,其他变量请参考官方文档。

(1)fs.defaultFS——HDFS服务发布地址:

这里没有使用master1,而是使用了nameservices特性,配置了命名服务mycluster,至于这个nameservices是个什么东西,后面将会说明。

<property>
    <name>fs.defaultFS</name>
    <value>hdfs://mycluster:8020</value>
</property>

(2)hadoop.tmp.dir——hadoop文件父目录

这个变量将用作其他一些需要配置本地文件系统路径的base directory,当这类变量没有显式配置时,将使用这个值作为base directory。

<property>
    <name>hadoop.tmp.dir</name>
    <value>file:///home/hadoop/bigdata/hadoop_tmp</value>
</property>

当然,具体路径还是要根据实际情况来配置。

(3)ha.zookeeper.quorum——ZooKeeper服务集群

ZooKeeper会用于两个NameNode的Active节点选举。因为之前配置了五台服务器,所以此处把它们全部写上。

<property>
    <name>ha.zookeeper.quorum</name>
    <value>master1,master2,slave1,slave2,slave3</value>
</property>

5、配置hdfs-site.xml文件

这个文件也是在$HADOOP_CONF_DIR中。

(1)dfs.replication——HDFS文件系统每个block冗余备份数。

<property>
    <name>dfs.replication</name>
    <value>3</value>
</property>

(2)dfs.datanode.data.dir——DataNode中数据所存储的本地文件系统路径。

<property>
    <name>dfs.datanode.data.dir</name>
    <value>file:///home/hadoop/bigdata/hdfs_data_dir</value>
</property>

(3)dfs.namenode.name.dir——NameNode中数据所存储的本地文件系统路径。

<property>
    <name>dfs.namenode.name.dir</name>
    <value>file:///home/hadoop/bigdata/hdfs_name_dir</value>
</property>

(4)dfs.nameservices——自定义的HDFS服务名。

在但NameNode节点的集群中,对HDFS集群访问的入口是NameNode所在的服务器。但是在两个NameNode节点的HA集群中,无法配置单一服务器入口。所以需要指定一个逻辑上的服务名,这个服务名是自定义的。当外界访问HDFS集群时,入口就变为这个服务。用户不必关心当前具体是哪台服务器在提供服务(Active状态),只要访问这个服务就可以了。

<property>
    <name>dfs.nameservices</name>
    <value>mycluster</value>
</property>

(5)dfs.ha.namenodes.[nameservice ID]——每个NameNode的唯一标识

此处为两个NameNode的唯一标识,也是可以自定义的。在HDFS集群管理中会用到

<property>
    <name>dfs.ha.namenodes.mycluster</name>
    <value>nn1,nn2</value>
</property>

(6)dfs.namenode.rpc-address.[nameservice ID].[name node ID]——分别指定每个NameNode的RPC服务完整监听地址(hostname+端口号)

<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>

(7)dfs.namenode.http-address.[nameservice ID].[name node ID]——指定两个NameNode的http服务地址

<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>

(8)dfs.namenode.shared.edits.dir——QJM访问地址

在没有配置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>

(9)dfs.journalnode.edits.dir——Journal Node文件存储地址

<property>
    <name>dfs.journalnode.edits.dir</name>
    <value>/home/hadoop/bigdata/jnode_edits_dir</value>
</property>

(10)dfs.client.failover.proxy.provider.[nameservice ID]

HDFS客户端用来连接集群中Active状态节点的Java类,ConfiguredFailoverProxyProvider是目前唯一可以指定的类

<property>
  <name>dfs.client.failover.proxy.provider.mycluster</name>
  <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

(11)dfs.ha.fencing.methods

这是个值得好好说一下的配置。当配置了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>

(12)dfs.ha.automatic-failover.enabled——是否开启自动failover机制

因为我们是要配置自动切换Active状态的集群,所以这项必须为true

<property>
    <name>dfs.ha.automatic-failover.enabled</name>
    <value>true</value>
</property>

5、配置slaves文件

若$HADOOP_CONF_DIR下没有这个文件,请自行创建。指定DataNode节点,每行一个hostname。这样集群中下面配置的每个节点都将将开启DataNode服务。

slave1
slave2
slave3

6、启动HDFS集群

(1)启动JournalNode

当所有配置都完成以后,我们需要先启动JournalNode服务。在配置了JournalNode服务的每台服务器上执行

hadoop-daemon.sh start journalnode

(2)格式化NameNode

启动了JournalNode后(可以通过jps命令查看),我们需要格式化NameNode。在nn1(master1)上执行:

hdfs namenode -format

在另一台NN服务器nn2(master2)上执行:

hdfs namenode -bootstrapStandby

在每个JournalNode上执行:

hdfs namenode -initializeSharedEdits

(3)格式化ZooKeeper

在任意一台NN服务器上执行:

$HADOOP_HOME/bin/hdfs zkfc -formatZK

(4)启动HDFS

在任意NN上执行

$HADOOP_HOME/sbin/start-dfs.sh

至此,全部部署完成。访问master1:50070和master2:50070,查看集群状态,两台NN的状态应该为一台Active,另一台一台Standby。kill掉Active服务器上的NN进程,查看Standby服务器上的NN进程的状态是否变为Active,如果是,则部署成功。如果没有成功,请检查配置是否正确。