HBase不睡觉书
上QQ阅读APP看书,第一时间看更新

2.4 安装Hadoop

已经安装过Hadoop的用户可以跳过这个步骤。

在安装HBase之前先要安装Hadoop,这是HBase运行的基础。安装过的就跳过这个步骤,没有安装过的就看看我的安装过程。你不一定要严格按照我的过程来做,只要能装上Hadoop就行,我的安装过程权当抛砖引玉。由于Hadoop安装有一定的复杂度和难度,一步到位的安装方式容易出错。花费大量的时间来调试错误容易让人产生挫折感,进而放弃,所以安装Hadoop的过程最好分三步走,如图2-1所示。

图2-1

友情提醒:安装Hadoop或者HBase这种分布式系统最好用一些批量执行命令的小工具,比如pssh或者dsh就很不错,否则真是复制粘贴到令人疯狂。

2.4.1 安装Hadoop单机模式

已经安装过Hadoop的用户可以跳过这个步骤。

2.4.1.1 下载Hadoop发布包

我下载的是2.6.4版本,文件名是hadoop-2.6.4.tar.gz。如果你下载的版本号跟我的差别太远了,比如3.0.1之类的,连大版本都不一样了,建议你以apache官网的安装教程为准,因为版本不一样有可能安装方式也会变得不一样,但是你依然可以用我的安装教程来辅助你理解官方的教程。下载完成后查看一下你的系统分区情况。以下是我的系统分区情况:

现在我的磁盘的最大分区是/data,次大分区是/,我们要把Hadoop的数据文件夹放到/data下面,程序文件夹放到/usr/local下面。

这边要解释一下数据文件夹和程序文件夹:

现在我们下载的是Hadoop的发布包,Hadoop不需要安装,只需要解压运行就可以了,你可以把这个发布包看成是一个绿色软件。运行的模式类似Tomcat或者Maven,即运行文件夹只存放运行的程序,而具体存放数据的目录一般都设定为另外一个文件夹,跟程序文件夹分离。

言归正传,我们先把压缩包解压开:

再将hadoop文件夹重命名一下:

接着确保hadoop文件夹的权限是我们刚刚创建的hadoop用户可以操作的:

最后将hadoop文件夹移动到/usr/local下面去:

2.4.1.2 添加环境变量

这些环境变量是一定要设定的,否则Hadoop会用默认的路径,比如用home目录去放日志,这样你的系统分区会很容易被占满,然后整个Hadoop集群就会宕掉,出现奇怪的问题,甚至机器也不正常。排除这些故障会花掉你很多天的时间,所以,不如认真地把环境变量设定好。

切换到hadoop用户,并编辑~/.bashrc文件,添加以下环境变量:

注意:

  • HADOOP_HOME就是设置为我们刚刚移动过来的hadoop程序文件夹的路径。
  • HADOOP_PREFIX会被hadoop自带的$HADOOP_HOME/sbin/start-dfs.sh脚本用到,打开这个文件看下就知道这里为什么要设定HADOOP_PREFIX了。

HADOOP_HOME还是HADOOP_PREFIX

有的教程提到配置HADOOP_HOME,而官方教程说是配置HADOOP_PREFIX,那么究竟Hadoop是用哪个环境变量来标定Hadoop的程序文件夹位置?实际上是这样的,早期Hadoop主要用HADOOP_HOME来标定程序文件夹位置,后来他们改成了HADOOP_PREFIX,所以为了兼容性,干脆都设置上,并且保持一样的值吧。

写完记得使用source命令加载~/.bashrc文件,让配置立即生效:

2.4.1.3 修改配置文件

配置hadoop-env.sh

编辑hadoop的$HADOOP_PREFIX/etc/hadoop/hadoop-env.sh文件,在文件开头添加以下变量:

这个配置最好不要按照默认配置来,因为:

  • JVM运行的内存如果不设定占用大小的话,要么不够,要么就把机器的内存都占满了。曾经有一次我们项目组花了整整一个星期来解决Hadoop集群的节点频繁地自己挂掉的问题,最后发现是内存分配不足造成的。之后我就养成了只要用到JVM的地方都加入内存参数,至少内存多少自己心里有数,让情况可控。
  • 日志文件路径如果不设定的话,多半后期会遇到放日志的分区满了,各种奇怪故障层出不穷。

接下来,记得创建日志文件夹,并分配正确的权限,切换到root用户(顺便说一句,Hadoop一定要有root权限,否则寸步难行,如果你的网管不给你root权限你就可以罢工了!其实只需要安装的时候暂时给一下root权限就行了。没错,你可以拿着这本书上的这句话作为证据给他看,不用谢),然后运行:

配置core-site.xml

顾名思义,这个文件就是配置Hadoop的Web属性的文件。我们需要在<configuration>节点中增加配置项,添加后的<configuration>节点是这样的:

提示

有的教程让你把端口配置成9000,那是比较早期版本的Hadoop,后来Hadoop把端口修改为8020了。更具体的属性说明请查阅Hadoop官网。

编辑hdfs-site.xml

这个文件负责配置HDFS相关的属性。我们需要在<configuration>节点中增加配置项,添加后的<configuration>节点是这样的:

说明:

(1)dfs.replication是用于设置数据备份的,我们只是学习,所以暂时设置为1。实际开发中请千万不要设置成1,因为Hadoop的数据很容易坏。坏了不是问题,只要有备份就不算真得坏,Hadoop会自动使用备份;但是如果没有备份,就比较麻烦了。

(2)dfs.namenode.name.dir是namenode在硬盘上存储文件的位置,有的教程用dfs.name.dir,这是比较早期的参数名,现在已经淘汰。

(3)dfs.datanode.data.dir是datanode在硬盘上存储文件的位置,有的教程用dfs.data.dir,这是比较早期的参数名,现在也已经淘汰。

为什么在namenode上也要设定datanode的存储目录

其实为namenode节点设置datanode的存储目录的确没什么意义。不过在所有节点上用同一份配置文件是Hadoop官方的要求,所以哪怕是namenode节点的配置文件,也包含有datanode的存储目录。这样做的理由是:

(1)实际生产环境中有可能有成百上千台机器,为不同角色的机器设定不同的配置文件实在太麻烦,干脆就都用同一份文件,各个角色分别读取属于自己的配置项就好了。

(2)配置文件经常需要更新,用同一份文件的好处就是,当配置更新的时候,全部批量覆盖一遍就好了,简单粗暴。

配置完记得去创建这几个文件夹。我用root权限建立这些文件夹并赋权限:

2.4.1.4 格式化namenode

切换到hadoop用户,然后用hdfs命令格式化namenode:

2.4.1.5 启动单机模式

我们现在要用start-dfs.sh(这个文件不在我们熟知的bin里面而是在sbin里面)命令来启动hadoop。

你可能要问:我们现在只是配置了nn01这一台机器,那datanode之类的其他节点都还没有配置,怎么就启动了?是这样的,现在我们用start-dfs.sh启动hadoop,hadoop就会在nn01上同时启动namenode、secondary namenode、datanode。这样一来,nn01就是一个独立节点模式(single node)的hadoop集群(严格来说都不算是个集群,不过姑且这么称它吧),这就是单机模式。这样做的好处有:

  • 你可以验证你的配置是否正确。
  • 通过前面辛苦的配置你可以看到一点成果,让自己有动力继续做下去,而且是放心地继续往下做。
  • 可以先熟悉一下Hadoop的一些基本界面和操作,为后面更复杂的配置打基础。

启动的时候注意看有没有什么异常,启动完记得看看启动日志有没有什么异常。

通过tail命令查看启动日志:

这里的具体日志名根据机器的名字不同而不同。日志文件存放的位置就是我们之前配置的HADOOP_LOG_DIR。

用浏览器访问Hadoop控制台

确定没看到什么问题后,打开浏览器访问http://nn01:50070/。如果没问题的话就可以看到以下画面,如图2-2所示,这里的nn01是我配置的服务器名,你可以换成你配置的服务器名,或者直接输入ip也可以。

图2-2

看到这个画面,你就可以庆祝一下了,开瓶啤酒,吃个辣翅,你终于看到Hadoop长什么样子了!

提示

如果想停止单机模式的Hadoop,使用命令:stop-dfs.sh

2.4.2 安装Hadoop集群模式

已经安装过Hadoop的用户可以跳过这个步骤。

接下来把我们的集群装上。第一件要做的事情就是把我们在单机模式上配置好的文件夹复制到其他机器上,把环境变量再配置一遍。

2.4.2.1 准备工作

(1)把nn01上的hadoop文件夹复制到其他机器上的/usr/local文件夹下,并确保权限正确。我用的是以下命令。

在nn01上用hadoop执行:

在nn02上用root执行:

修改core-site.xml中的fs.defaultFS属性为该服务器的hostname,比如hdfs://nn02:8020。

(2)在所有机器上切换到hadoop用户,然后在~/.bashrc内增加以下环境变量:

不要忘记用source命令让这些环境变量生效。

(3)在所有机器上建立必要的文件夹。建立数据文件夹:

建立日志文件夹:

(4)在所有机器上格式化namenode(仅仅用来调试,不代表这些机器都要用作namenode)。

(5)在所有机器上用start-dfs.sh启动单机模式,通过日志和浏览器访问<hostname/IP>:50070来确保所有机器上的配置都是正确的。

提示

如果想停止单机模式的Hadoop,就用stop-dfs.sh。

单机模式都正常后,用stop-dfs.sh来停止所有节点的单机模式,然后把所有节点上的core-site.xml内的fs.defaultFS值都设置成hdfs://nn01:8020,因为我们接下来要把所有的节点按不同的角色启动起来,并连接起来。

清空数据文件夹

请先别激动,我们要先清除单机模式留下来的数据。在保证所有节点都停止后,在所有节点上清空数据文件夹。

在dn01~dn03(我的所有datanode节点)上删除namenode数据:

在所有节点(namenode和datanode都要)上删除datanode数据:

2.4.2.2 连接节点成为集群

终于到了要连接起一个集群的时候了!请进行以下步骤:

(1)在nn01(我的第一个namenode节点)上用hadoop用户执行以下命令来启动namenode:

如果想停止的话,把上面这条命令的start换成stop就可以了。

用jps命令(这个命令很好用,可以查看当前运行的hadoop进程)执行如下:

(2)nn02(我的第二个namenode节点)不需要启动,等后面配置HA的时候再用它。现在暂时用不上它。

(3)在dn01~dn03(我的datanode节点)上清空datanode文件夹:

并用以下命令启动datanode:

如果想停止的话,把上面这条命令的start换成stop就可以了。

同样用jps命令检查一下datanode是否有启动。

(4)接下来打开nn01的控制台。方法是,用浏览器访问nn01(我的第一个namenode节点)的50070端口,并切换到Datanodes标签。如果你看到出现了3个datanode,说明datanode 跟namenode之间连接起来了!如图2-3所示。

图2-3

datanode跟namenode是怎么连接起来的

datanode通过core-site.xml中的fs.defaultFS属性去连接namenode的8020端口,一旦连上它们之间就会建立联系,该datanode就会成为namenode的数据节点。

2.4.3 ZooKeeper

在继续把Hadoop配置成HA之前,必须要提的是ZooKeeper。ZooKeeper不止Hadoop的HA模式用到,HBase也会用到,所以它是必装组件。ZooKeeper也是Apache旗下的一个开源项目,如图2-4所示。它是一个开放源码的分布式应用程序协调服务,是Google Chubby的一个开源的实现,也是Hadoop和HBase的重要组件。它可以为分布式应用提供一致性服务,所提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

图2-4

ZooKeeper最大的功能之一是知道某个节点是否宕机了,那么ZooKeeper是如何知道某个节点宕机了呢?

答案是,每一个机器在ZooKeeper中都有一个会话(Session),如果某个机器宕机了,这个会话(Session)就会过期,与此同时,ZooKeeper就会知道该节点已宕机。

接下来我们具体来安装一下。

(1)首先要知道ZooKeeper的节点总数最好是奇数,这样有利于仲裁。偶数个节点,如果遇上五五开就判断不出结果了。正好我的节点数是5个,所以我就把5台机器都装上ZooKeeper。先创建zookeeper用户:

(2)从ZooKeeper官网上把发布包下载下来。我下载的是3.4.6版本,所以文件名是zookeeper-3.4.6.tar.gz。解压开,并移到/usr/local目录下,最后把用户修改为zookeeper.zookeeper:

(3)配置环境变量。

切换到zookeeper用户,在/etc/profile中增加:

然后用source/etc/profile命令让配置生效(这次用/etc/profile,是因为这个文件设置的是全局变量,之前那个~/.bashrc是单用户的变量,其实他们之间的区别并不只是这个,不过不属于本书讨论范围)

(4)配置ZooKeeper。

把/usr/local/zookeeper/conf/zoo_sample.cfg文件复制一份,改名成zoo.cfg,然后编辑这个文件,其他的部分不用动,只需要修改dataDir这一行。dataDir是ZooKeeper的数据文件夹的位置,在我的机器上我用的是/data/zookeeper,你们可以设置成你们的目录。

修改bin/zkEnv.sh,在该文件的ZOOBINDIR= "${ZOOBINDIR:-/usr/bin}"行以上增加日志输出文件夹的配置(我喜欢把日志都放到/data/logs文件夹下,这个文件夹的定位比较随意,你们可以根据自己的喜好来定义):

提示

不要把配置写到#!/usr/bin/env bash这行的上面去,因为这行是脚本的头部用来声明执行脚本的工具,如果你把代码放到它上面,这行代码就无法被解析了。

不要忘记使用root用户去建立这些文件夹,并分配正确的权限:

(5)在每一台机器上的dataDir(我配置的是/data/zookeeper)目录下手动建立一个文 件,命名为myid,并写入这台服务器的ZooKeeper id(是集群模式才需要的文件)。这个id数字可以自己随便写,取值范围是1~255。在这里我给每一台机器赋上id,如表2-1所示。

表2-1 每一台机器赋上id

以nn01来举例,在nn01上执行:

在别的机器上只需要把1换成具体的id就好了。

(6)切换到zookeeper用户下启动ZooKeeper。

启动后用$ZOOKEEPER_HOME/bin/zkCli.sh测试一下是否可以连上。如果没报什么错误,用ls/命令看下是否可以查看ZooKeeper根目录的东西:

(7)将ZooKeeper配置到所有节点上。

在连接各个ZooKeeper节点之前,我们先要把刚才ZooKeeper启动后产生的数据删除,否则当ZooKeeper集群启动后会报错。具体方法是:用$ $ZOOKEEPER_HOME/bin/zkServer.sh stop来停止ZooKeeper,然后清空数据文件夹和日志文件夹:

编辑 $ZOOKEEPER_HOME/conf/zoo.cfg,在末尾加上所有节点的信息:

ZooKeeper会自动根据这里的配置把所有的节点连接成一个集群。

接着,把所有其他节点都装上ZooKeeper并配置好,最后一并启动起来。

(8)检查一下日志,再用jps看看进程有没有启动起来。

一切正常就可以继续进行下一步了。

(9)添加ZooKeeper到自启动脚本。

这个步骤是可选的,可以不做,但是添加自启动脚本是一个好习惯,免得重启之后完全忘记之前是怎么启动这些服务的了。我经常重启服务器,如果不设定自启动脚本,那么,每次都需要把启动服务的那些命令都敲一遍,非常费时。

用root账户在/etc/init.d下建立一个文件叫zookeeper,内容如下(请自行替换JAVA_HOME变量为你机器的JDK所在目录路径)。

提示

下面脚本只适用于CentOS 6及以下版本,不适用于CentOS 7。如果你使用的是CentOS 7,你需要自行编写并创建systemd服务。systemd极大地简化了服务脚本的编写,不过具体创建的方法请自行咨询资料。

保存之后给它一个可执行权限:

你可以用service命令来测试一下这个服务是否正常(要在root用户下才能执行service):

使用chkconfig来添加服务到自启动:

现在,你可以重启一下机器测试这个自启动脚本是否生效。

2.4.4 配置Hadoop HA

已经安装过Hadoop的用户可以跳过这个步骤。

接下来我们要为Hadoop配置上HA。HA的作用是保证在一个namenode挂掉的时候,另外一个namenode可以立即启动来替代这个挂掉的namenode。这样就不会发生单点故障问题。实现原理简单来说就是:

  • 同时启动两台namenode,一台是active状态(活跃状态,真正在工作的),另外一台是standby状态(它唯一要做的事情就是把active状态的namenode做过的所有事情同步过来,方便在第一台namenode故障的时候可以无缝切换)。
  • 设想一下,既然是故障恢复方案,总得有那么一个机制是用来检测故障的,比如做系统心跳之类的,是吧?在HA方案中,Hadoop集群利用ZooKeeper来做节点维护,具体的就是节点的故障检测、状态标定等。这些杂事要自己来写也是很麻烦的,所以Hadoop就把这些事情交给了ZooKeeper。当ZooKeeper检测到active节点已经宕机,就会启动切换机制。
  • 之前提到standby状态的namenode所做的唯一的事情就是同步active状态节点的数据,那么也需要一个数据同步的机制,是吧?这块无论是让哪个namenode来做都不是很合适。所以,在这里又引入了一种新的节点,叫做journalnode。这种节点专门用于同步namenode的所有操作。standby节点就是通过journalnode集群来同步active节点的操作。

2.4.4.1 JournalNode

JournalNode跟namenode、datanode一样,只是Hadoop集群中的一个角色,用于同步两个namenode之间的操作,并防止“脑裂现象”发生(关于脑裂现象,我会在后续的章节继续介绍,目前你不需要了解的太多)。JournalNode的配置相对简单,一般只需要配置数据文件夹dfs.journalnode.edits.dir的位置就好了。我们在下面的手动HA配置里面会一起配置这个属性。

有时候你会发现namenode自杀了

有时候你会发现namenode自己停掉了(就是自杀了)。看日志会发现它留下了这样一行话:

然后就自杀了:

遇到这种情况,如果你的机器配置恰好不是很好(生产环境的机器CPU建议值是8核~12核,内存是8GB~16GB,而测试的机器通常来说没有那么好),这时你可以在hdfs-site.xml里面添加dfs.qjournal.start-segment.timeout.ms的配置,来增加跟journalnode集群之间通信的超时时间:

但是,在生产环境下,凡是这些关于超时的参数都是在可接受范围内越小越好。因为集群越小对于故障的反应越及时,你的网站客户感受到故障的时间也就越短。

2.4.4.2 手动failover配置

所谓failover就是故障切换。当Hadoop有一台namenode宕掉了,可以切换到另外一台。或者两台都是standby状态的情况下,选出一台来做active的namenode。

failover可以手动操作,也可以配置成自动。之所以叫HighAvailable,是相对于单点故障而言。当系统只有一台namenode,而这台namenode正好宕掉的话,整个集群就瘫痪了,这就是所谓的单点故障问题。而配置上自动failover之后,当其中一台宕掉了,另一台会迅速地自动进入active状态,开始工作。

我们先从手动failover开始。

在自动failover之前,先做好手动failover配置。请先停止之前的所有Hadoop进程,再进行下面的步骤。

1.hdfs-site.xml

在所有节点上修改$HADOOP_PREFIX/etc/hadoop/hdfs-site.xml文件(为了简化操作你可以在一台机器上做,然后把文件批量推送到其他服务器上,可以用类似pscp这样的工具)

STEP 1 增加服务id(nameservice ID,我管它叫集群ID)

现在有两个namenode了,你不能写死用哪个namenode,因为他们会互相切换,所以就有了一个新的概念,就是——服务id:

STEP 2 配置服务id内含有的namenode

此处mycluster就是你刚刚配置的服务id名称,如果你换了个名称,比如alexcluster,那么,配置名就要叫做dfs.ha.namenodes.alexcluster。此处使用mycluster作为服务id:

STEP 3 配置这两个namenode的rpc访问地址

还记得core-site.xml的fs.defaultFS吗?在HA模式下8020端口的配置移到这里来了:

STEP 4 配置namenode的http访问地址

STEP 5 配置journalnode集群的访问地址

“不要把鸡蛋都放到一个篮子里”。工作中如果条件允许,请单独分配几台机器来搭建jouralnode集群(ZooKeeper集群可以安装到journalnode集群的机器上来节省成本)。namenode如果宕掉了,往往不只是namenode本身的问题,有可能那台服务器有问题,比如网络不通,或者硬盘坏了,这样一来,这台服务器上别的服务也会有问题。如果把journalnode配置到namenode上,那么当namenode机器挂掉的时候,这个journalnode节点也会跟着一起坏掉。

STEP 6 配置dfs客户端

dfs客户端的作用是判断哪个namenode是活跃的,我们现在要配置dfs客户端的Java类名。

目前就一个实现,除非你要自己自定义一个类,否则照着这个配置写就对了:

STEP 7 配置杀(Kill)掉namennode的方式

杀掉死掉的节点,是为了让活的节点活得更好。当需要“故障切换”(failover)发生的时候,被判断为故障的namenode有可能停止不下来,这样就有可能引发“脑裂现象”。关于“脑裂现象”的解释,详见“2.4.4.3脑裂现象”。为了防止这种情况,需要配置一个终极解决方案,比如直接SSH过去kill掉它!我们配置成SSH手段就好了。

此处,private-key-files配置成之前我们配置的SSH免密登录所生成的id_rsa文件,因为Hadoop到时候会用这个文件来免密登录到另外一个namenode上去kill掉进程。

配置journalnode的数据文件夹位置:

2.core-site.xml

修改core-site.xml文件。

将之前的fs.defaultFS从:

换成:

这个地方的8020端口配置移到hdfs-site.xml里面了。namenode对外开放的URI不再需要指定单独的机器和端口了,因为两个namenode已经组成了一个服务集群,对外只需要暴露服务ID(nameservice ID)就可以了。

至此你可能会有疑惑:

给我一个id,我还是不知道怎么连接上去,因为计算机网络的访问本质还是需要一个ip和端口啊!

答案是各个客户端都是拿这个服务ID(nameservice ID)去ZooKeeper集群中查出活跃状态(active)的namenode的ip和端口,再进行连接的。

3.journalnode

建立journalnode需要的数据文件夹。

启动journalnode。你想启动几个journalnode就启动几个,在这里除了数量必须是奇数的以外没有别的要求。我用作例子的机器有5台,所以我就在5台上都启动journalnode。启动的命令如下:

同样地,不要敲完命令就不管了,下面几个事情还是要照做的。

(1)用jps看看有没有JournalNode进程启动。

(2)如果没有就看看journalNode的日志,解决一下错误。启动日志在你启动后会有一句话输出,比如:

(3)如果想停止,就把启动命令中的start换成stop就行了。

4.格式化namenode

在第一个namenode上进行格式化。我的机器是nn01,所以我就在nn01上执行以下命令:

接下来,初始化第二个namenode。这样做的目的是清空第二个namenode,让它完全做好作为备份机的准备。我的第二个namenode是nn02,所以我在nn02上执行:

然后初始化journode中的记录,在第一台namenode上(nn01)执行以下命令:

5.启动namenode

在两个namenode上都用以下命令启动namenode:

之后,你可以打开浏览器访问这两个namenode的50070管理页面。你会发现这两个namenode的名字后都出现了一个括号来显示他们的状态,现在他们都处于备份(standby)状态。这是因为在HA中的namenode启动的时候都是standby状态,只有执行了手动切换或者自动切换后才会变成active状态,如图2-5所示。

图2-5

6.执行手动failover

手动failover即手动切换namenode。我们现在还没有配置自动故障切换(Auto Failover),所以两台机器并不知道它们中的谁应该是激活(active)状态,所以他们不会做任何动作。我们现在要用手动的方式来把其中一台机器切换为active(虽然在实际的生产环境下基本都是靠自动切换,不过未雨绸缪,手动总有一天是可以派上用场的)。手动切换可以用haadmin命令。由于我有两个namenode:nn01和nn02,因此我要把nn01切换为激活(active)状态,需要执行的命令如下(如果你们的namenode叫另外的名字请自行替换命令中的hostname):

这个命令的意思是强制把nn02切换为standby状态(现在nn02已经是standby状态了,所以不会对nn02有什么影响),把nn01切换到active状态。这个命令如果执行成功的话,会打印出一句话:

这个时候我们再去看nn01的控制台,如图2-6所示。

图2-6

我们可以看到,nn01的状态已经被成功地切换成active了。

2.4.4.3 脑裂现象

Kill掉非正常的namenode的目的就是防止脑裂现象。因为zkfc判断namenode是否宕机是基于超时机制的。如果当时网络状况不好,或者机器负载过重造成响应很慢,也有可能被判断为宕机。一旦判断该机为宕机,zkfc会立即去将另外一个standby的namenode设置为active状态。此时由于之前那台active的namenode有可能进程还活着,客户端还在往里面写数据,如果不将其kill掉,等这台被误认为是已经宕机的namenode恢复了工作后,就会造成系统中同时有两个namenode在工作,数据就混乱了,这就是脑裂现象。

这时候同时有两个namenode在操作datanode,该问题如图2-7所示。

图2-7

2.4.4.4 zkfc

要防止脑裂现象的发生,首先要有一个机制来自动检测哪台namenode宕机了。Hadoop zkfc就是用于自动检测namenode是否宕机的服务。如果宕机就自动将另一个standby状态的namenode启动,并将当前已宕机的namenode上的namenode进程杀死(kill -9)以防止脑裂现象的服务,也就是自动failover过程。

zkfc好像不是那么稳定

使用zkfc的时候,你会发现在硬件条件不那么好的情况下,zkfc不稳定。就像我们在做这篇教程的时候,使用的实验机器一般都不会像生产环境那么好(生产环境CPU要8~12核,内存要8GB~16GB),很可能你会跟我一样经常遇到重启后zkfc就启动不起来了的问题(说白了都是因为穷啊)。仔细看日志,你会发现zkfc一般都是超过5s连不上ZooKeeper就自动退出了。为了解决此类问题,我们需要提高ha.zookeeper.session-timeout.ms的设置(我在试验环境下设置它为30000)。我们可以在core-site.xml中加入这段配置:

不过这并不代表把这个参数设置得越大越好。相反地,生产环境中这个参数越小越好。因 为越大意味着zkfc越迟知道namenode宕掉了,在namenode宕掉后zkfc没及时判断它为宕机并去切换另一个namenode为active的这段时间内,你的网站用户的体验一定很糟糕。

2.4.4.5 配置自动failover

自动failover是基于ZooKeeper的,所以请先确保ZooKeeper已经都启动了。如果没有就先启动ZooKeeper集群。

按以下步骤配置自动failover(配置的修改跟之前一样,在一个地方修改后推送到所有机器上去):

(1)添加自动failover配置到hdfs-site.xml内。

(2)因为auto failover是基于ZooKeeper的,所以我们要把ZooKeeper集群的访问地址配置进去。

我在5台机器上都启动了ZooKeeper,所以我配置了5个地址,你可以根据自己的需要修改ZooKeeper集群的配置。

(3)初始化ZooKeeper集群。

使用Hadoop自带的hdfs工具初始化ZooKeeper集群。随便在一台只要能访问到ZooKeeper集群的机器上,这里我在nn01(我的第一个namenode)上操作初始化ZooKeeper的动作。执行以下命令:

执行完后用$ZOOKEEPER_HOME/bin/zkCli.sh看下集群的目录情况:

可以看到多出来一个hadoop-ha目录,说明初始化正确。

(4)我们来把namenode都停掉,再启动起来,让它们都进入standby状态。

在两台机器上都停止namenode:

然后启动namenode:

启动之后通过浏览器访问<hostname>:50070控制台,可以看到两台namenode目前都处于standby状态。这回我们不使用手动failover,我们使用zkfc的自动failover功能让他们中的其中一台namenode自动切换为active。

(5)启动zkfc。

Hadoop有一个zkfc进程,这个进程用户跟ZooKeeper通信,然后根据通信的结果来进行故障切换(failover)。所以,实际上是这个进程在帮我做自动的failover。首先,在两个namenode上都执行以下命令:

用jps查看进程是否启动了:

(6)验证自动failover。

打开浏览器访问两个namenode的控制台<hostname>:50070,你会发现此时至少有一个namenode变为了active状态。这说明自动failover成功了!

自动failover成功后,先别急着安装HBase。之前我们这些进程(除了ZooKeeper,因为我们之前做过一次了)都是手动启动的,电脑总有关机重启的时候,要是重启了,那些服务可就都没了,所以我们还要做一些收尾工作,在进行以下操作之前,请先关闭整个Hadoop集群。

(7)由于做HA的过程中namenode被格式化了,所以我们需要把之前的datanode数据文件夹清空,以避免datanode由于找不到自己的数据块在namenode中的注册信息而连接不上namenode的情况发生:

然后,先启动namenode,再逐个启动datanode,看各个datanode在namenode控制台UI中是否正确地被显示出来。

(8)让Hadoop可以开机自启动。

2.4.5 让Hadoop可以开机自启动

已经安装过Hadoop的用户可以跳过这个步骤。

类似之前给ZooKeeper做开机自启动的例子,我们需要把Hadoop的namenode、datanode和journalnode都做成可以开机自启动。

只需要两个步骤:

(1)用一个脚本把进程做成服务。

(2)把这个服务用chkconfig添加到开机自启动。

但是,要注意各个服务启动顺序,如图2-8所示。

图2-8

我们在设置chkconfig的启动和停止顺序的时候也要按照这个顺序操作。

2.4.5.1 先添加journalnode到开机自启动

切换到root用户,在/etc/init.d/下建立hadoop-journalnode脚本,并推送到所有服务器:

提示

以下脚本只适用于CentOS 6及以下版本,不适用于CentOS 7。如果你使用的是CentOS 7,你需要自行编写并创建systemd服务。systemd极大地简化了服务脚本的编写,不过具体创建的方法请自行查询。

这回我们把原先在ZooKeeper自启动脚本中的那句export JAVA_HOME=”xxxxxx”替换成./home/hadoop/.bashrc(注意不要少了前面的.符号)。这是因为之前ZooKeeper只需要一个JAVA_HOME环境变量就够了,但是这回namenode需要的环境变量有好几个,一排写下来太冗长了。我们可以通过直接读取Hadoop的.bashrc文件获取到这些环境变量。这样做还有一个好处就是:一处修改,全局生效。

我们还把chkconfig的启动顺序改为81,关闭顺序改为09,这是相对于ZooKeeper的启动顺序为80,关闭顺序为10的设定而定,保证journalnode在ZooKeeper之后启动,并在ZooK eeper关闭之前关闭。

接着给这个脚本赋予可执行权限:

然后添加这个服务到自启动列表:

2.4.5.2 把namenode添加到开机自启动

切换到root用户,在/etc/init.d下建立一个服务脚本,命名为hadoop-namenode,内容如下:

提示

以下脚本只适用于CentOS 6及以下版本,不适用于CentOS 7。如果你使用的是CentOS 7,你需要自行编写并创建systemd服务。systemd极大地简化了服务脚本的编写,不过具体创建的方法请自行查询。

请记得把这个配置推送到另外一个namenode上。

接着给这个脚本赋予可执行权限:

然后添加这个服务到自启动列表:

接下来,把这个脚本推送到另外一个namenode上。我们可以尝试用service hadoop-namenode start启动namenode,以检测我们的脚本是否正确。

如果你遇到启动失败的状况,并且出现类似这样的错误信息:

请不要慌张,只需要在这台namenode上再次执行以下命令:

它会重新初始化这个namenode,然后就可以正常启动了。

2.4.5.3 添加zkfc到自启动

在/etc/init.d下建立hadoop-zkfc脚本,并推送到所有安装了zkfc服务的服务器上。这里的启动优先级设置为98,是所有Hadoop服务中最后启动的。zkfc如果启动得太早,跟ZooKeeper连接不上的话,它就会自动停掉。

提示

以下脚本只适用于CentOS 6及以下版本,不适用于CentOS 7。如果你使用的是CentOS 7,你需要自行编写并创建systemd服务。systemd极大地简化了服务脚本的编写,不过具体创建的方法请自行查询。

赋予可执行权限和添加到自启动的步骤跟之前的一模一样,就不赘述了。

2.4.5.4 最后把datanode添加到开机自启动

最后我们建立脚本叫hadoop-datanode,并把它推送到所有datanode上去。脚本的内容如下(其实就是把hadoop-namenode脚本中的namenode字样换成datanode而已):

提示

以下脚本只适用于CentOS 6及以下版本,不适用于CentOS 7。如果你使用的是CentOS 7,你需要自行编写并创建systemd服务。systemd极大地简化了服务脚本的编写,不过具体创建的方法请自行咨询资料。

赋予可执行权限和添加到自启动的步骤跟之前的一模一样,就不赘述了。

最后不要忘记把所有机器重启一遍来测试我们的自启动脚本是否生效。

检查成功与否的标准是:

(1)检查所有机器上的jps看是否正常。

(2)打开namenode的<hostname>:50070控制台看当前集群状态是否正常。

如果一切正常,你可以在控制台的Datanode标签页看到所有的Datanode,如图2-9所示。

图2-9

2.4.6 最终配置文件

以下是我最终的配置文件,作为例子供大家参考。