CentOS下Hadoop及ZooKeeper环境搭建

1. 测试环境

  • 操作系统 CentOS 6.5。
  • 总共5台机器,前两台作为namenode,称之为 nn01、nn02;后三台作为datanode,称为 dn01、dn02、dn03。
  • 每台机器的内存为8GB。确保每台机器都有 8GB 以上内存,因为 HBase 对配置的要求很高,如果低于 8GB,有可能会卡到,出现各种超时故障。
  • 每台机器的硬盘为 60GB。只要保证有一个分区达到30GB以上就可以了,到时候用这个分区来存放Hadoop和HBase的数据和日志。
  • JDK版本为Oracle JDK1.7。

2. 配置服务器名

配置 /etc/hosts 文件,将所有机器的IP地址和机器名都配置到hosts文件里面去,这样可以通过服务器名来SSH或者访问机器,而不用直接输入IP地址:

192.168.78.50 nn01
192.168.78.51 nn02
192.168.78.52 dn01
192.168.78.53 dn02
192.168.78.54 dn03

配置本机的 hostname。如果在Linux下使用指令 hostname 打出来的是奇怪的名字,或者不是你想要的,你就要修改 hostname, 否则 HBase 极易出现问题。由于我用的是CentOS系统,我编辑 /etc/sysconfig/network 文件,修改 HOSTNAME 这个配置项,比如:

HOSTNAME=dn03

最后,重启一下就会生效了。

3. 配置 SSH 免密登陆

首先确保五台机器之间有一个用户可以免密登陆到其他的机器上。假设你已经装完了Hadoop,那么你应该已经有一个用户可以用于免密登陆的,否则,估计你也装不成Hadoop。如果没有这样一个用户的话,你需要先配置它。
这个用户的要求是:

  • 可以通过sudo命令来以root权限运行命令。
  • 可以不加密码,直接用SSH在别的机器上执行命令。
  • 所有机器上都要有这个用户,名字和权限完全相同。
  • 该用户最好不要是root,当然用root也可以,只是生产环境没人这个干,太危险了!
  • 如果你不知道怎么取名,就跟我一样用 hadoop 这个用户名吧。

具体如何创建该用户以及配置上SSH,在不同的操作系统中有不同的配置。
这里我使用的用户名是 hadoop。我的操作系统是 CentOS 6.5,以下是我的具体操作步骤:

1. 登陆到 nn01 上

(1) 切换到 root 用户,然后建立 hadoop 用户。

# useradd hadoop
# passwd hadoop
New passwd:
Retype new passwd

(2) 添加 hadoop 到 sudoers 列表(以下命令以root用户执行):

chmod u+w /etc/sudoers

然后用vi编辑器打开sudoers文件,在里面添加一句话:

hadoop ALL=NOPASSWD:ALL

(3) 生成rsa密钥:

$ ssh-keygen -t rsa

采用默认配置,即默认目录和空密码。
然后检查 /home/hadoop/.ssh 目录,可以看到 id_rsa.pub 文件,这个就是我们这台机器中 hadoop 用户的公钥,我们要把这个文件传输到 host2 上。

(4) 传输公钥到host2:

scp ~/.ssh/id_rsa.pub hadoop@nn02:/home/hadoop

中间会问你:

Are you sure you want to continue connecting (yes/no)?

记得一定要回答yes。

nn02上

接下来用 hadoop 用户 SSH 到 nn02 上执行以下步骤。

(1) 确认是否存在 ~/.ssh 目录,如果不存在就创建一个。
给.ssh文件夹赋予700权限:

chmod -R 700 ~/.ssh

(2) 把我们刚刚传输过来的公钥的信息复制到 authorized_keys 内:

cat id_rsa.pub >> ~/.ssh/authorized_keys

注意 authorized_key 的权限:如果 authorized_keys 之前没有,那么 cat 命令创建出来的 authorized_keys 文件默认权限是 664,你需要修改权限为 600,否则由于这个文件的权限过大,在 SSH 的时候还是会要求你输入密码。

回到 nn01 去测试:

ssh nn02

会发现你已经可以直接登陆到 nn02 上,而不需要输入用户名和密码。
之后,把这个步骤在其他机器上也做一遍,确保机器之间都可以互相SSH,包括自己都可以SSH自己。比较简单的方式就是把5台机器的id_rsa.pub文件放到一起打个包,然后传输到所有机器上,最后用 cat 追加进 authorized_keys 文件里面去。

做完这些后,请仔仔细细地把所有机器都测试一遍。

4. 安装 Hadoop

在安装 HBase 之前先要安装 Hadoop,这是 HBase 运行地基础。

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

4.1 安装 Hadoop 单机模式

4.1.1 下载 Hadoop 发布包

下载 2.6.4 版本,文件名是 hadoop-2.6.4.tar.gz。

下载完成后查看一下你的系统分区情况。以下是我的系统分区情况:

[hadoop@50 etc]$df -h
Filesystem          Size    Used    Avail   Use%    Mounted on
/dev/sda3           8.6G    1.6G    6.6G    20%     /
tmpfs               3.9G    0       3.9G    0%      /dev/shm
/dev/sda1           190M    72M     109M    40%     /boot
/dev/sda5           4.7G    525M    4.0G    12%     /home
/dev/sda7           969M    1.3M    917M    1%      /tmp
/dev/sda6           4.7G    112M    4.4G    3%      /var
/dev/mapper/vg_00-1v--data      49G     1.1G    45G     3%      /data

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

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

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

首先解压压缩包:

tar zxvf hadoop-2.6.4.tar.gz

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

mv hadoop-2.6.4 hadoop

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

# chown hadoop.hadoop hadoop

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

# mv hadoop /usr/local/

4.1.2 添加环境变量

这些环境变量是一定要设置的,不然Hadoop会用默认的路径,造成一系列不必要的问题。
切换到 hadoop 用户,并编辑 ~/.bashrc 文件,添加以下环境变量:

export HADOOP_HOME=/usr/local/hadoop
export HADOOP_PREFIX=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin
export HADOOP_INSTALL=$HADOOP_HOME

注意:

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

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

$ source ~/.bashrc

4.1.3 修改配置文件

配置 hadoop-env.sh
编辑 hadoop 的 $HADOOP_HOME/etc/hadoop/hadoop-env.sh 文件,再文件开头添加以下变量:

export HADOOP_NAMENODE_OPTS=" -Xms1024m -Xmx1024m -XX:+UseParallelGC"
export HADOOP_DATANODE_OPTS=" -Xms1024m -Xmx1024m"
export HADOOP_LOG_DIR=/data/logs/hadoop

接下来,记得创建日志文件夹,并分配正确的权限,切换到 root 用户,然后运行:

mkdir /data/logs
mkdir /data/logs/hadoop
chown hadoop.hadoop /data/logs/hadoop

配置 core-site.xml
这个文件是配置 Hadoop的Web属性的文件。我们需要再

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

编辑 hdfs-site.xml
这个节点负责配置 HDFS 相关的属性。我们需要在

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
    <property>
        <name>dfs.namenode.name.dir</name>
        <value>file:///data/hadoop/hdfs/nn</value>
    </property>
    <property>
        <name>dfs.datanode.data.dir</name>
        <value>file:///data/hadoop/hdfs/dn</value>
    </property>
</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 权限建立这些文件夹并赋权限:

# mkdir -p /data/hadoop/hdfs/nn
# mkdir -p /data/hadoop/hdfs/dn
chown -R hadoop.hadoop /data/hadoop

4.1.4 格式化namenode

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

$ hdfs namenode -format

4.1.5 启动单机模式

现在我们要用 start-dfs.sh 命令来启动hadoop:

$ $HADOOP_HOME/sbin/start-dfs.sh

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

  • 你可以验证你的配置是否正确。
  • 通过前面辛苦的配置你可以看到一点成果。
  • 可以先熟悉以下 Hadoop 的一些基础界面和操作,为后面更复杂的配置打基础。

启动的时候注意看有没有什么异常,启动完记得看看启动日志有没有什么异常。
通过 tail 命令查看启动日志:

tail -200f /data/logs/hadoop/hadoop-hadoop-namenode-50.log

用浏览器访问Hadoop控制台
浏览器访问: http://nn01:50070/ 。
若出现一个画面,显示 Started、Version、Compiled、Cluster ID、Block Pool ID等信息的,说明启动成功。

4.2 安装 Hadoop 集群模式

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

4.2.1 准备工作

(1) 把 nn01 上的 hadoop 文件夹复制到其他机器上的 /usr/local 文件夹下,并确保权限正确。
在 nn01 上用 hadoop 执行:

$ scp -r /usr/local/hadoop root@nn02:/usr/local/

在 nn02 上用 root 执行:

# chown -R hadoop.hadoop /usr/local/hadoop

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

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

export HADOOP_HOME=/usr/local/hadoop
export HADOOP_PREFIX=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin
export HADOOP_INSTALL=$HADOOP_HOME

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

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

建立数据文件夹:

# mkdir -p /data/hadoop/hdfs/nn
# mkdir -p /data/hadoop/hdfs/dn
chown -R hadoop.hadoop /data/hadoop

建立日志文件夹:

mkdir /data/logs
mkdir /data/logs/hadoop
chown hadoop.hadoop /data/logs/hadoop

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

hdfs namenode -format

(5) 在所有机器上用 start-hdfs.sh 启动单机模式,通过日志和浏览器访问

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

清空数据文件夹
我们要清除单机模式留下来的数据。在保证所有节点都停止后,在所有节点上清空数据文件夹。
在 dn01 ~ dn03 (我的所有 datanode 节点)上删除 namenode 数据:

$ rm -rf /data/hadoop/hdfs/nn/current

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

$ rm -rf /data/hadoop/hdfs/dn/current

4.2.2 连接节点成为集群

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

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

$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --script hdfs start namenode

如果想停止的话,把上面这条命令的 start 换成 stop 就可以了。
用 jps 命令(这个命令用于查看当前运行的 hadoop 进程)执行如下:

$ jps
1240 Jps
1197 NameNode

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

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

$ rm -rf /data/hadoop/hdfs/dn/current

并用以下命令启动 datanode:

$ $HADOOP_PREFIX/sbin/hadoop-daemons.sh --script hdfs start datanode

如果想停止的话,把上面这条命令的 start 换成 stop 就可以了。
同样用 jps 命令检查一下 datanode 有没有启动。

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

datanode 跟 namenode 是怎么连接起来的

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

4.3 ZooKeeper

在 Hadoop 的 HA 模式 及 HBase中都会用到 ZooKeeper。
ZooKeeper 可以为分布式应用提供一致性服务,所提供的功能包括:配置维护、域名服务、分布式服务、组服务等。

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

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

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

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

# useradd zookeeper
# passwd zookeeper

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

# tar zxvf zookeeper-3.4.6.tar.gz
# mv /home/zookeeper/zookeeper-3.4.6 /usr/local/zookeeper
# chown -R zookeeper.zookeeper /usr/local/zookeeper

(3) 配置环境变量。
切换到 zookeeper 用户,在 /etc/profile 中增加:

export ZOOKEEPER_HOME=/usr/local/zookeeper

然后用 source /etc/profile 命令让配置生效(这次用 /etc/profile ,是因为这个文件设置的是全局变量,之前那个 ~/.bashrc 是单用户的变量)

(4) 配置 ZooKeeper

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

...
dataDir=/data/zookeeper
...

修改 bin/zkEnv.sh,在该文件的 ZOOBINDIR="${ZOOBINDIR:-/usr/bin}"行以上增加日志输出文件夹的配置:

ZOO_LOG_DIR=/data/logs/zookeeper

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

# mkdir /data/zookeeper
# chown zookeeper.zookeeper /data/zookeeper
# mkdir /data/logs/zookeeper
# chown zookeeper.zookeeper /data/logs/zookeeper

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

服务器名 id
nn01 1
nn02 2
nn03 3
nn04 4
nn05 5

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

$ cat 1 /data/zookeeper/myid

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

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

$ $ZOOKEEPER_HOME/bin/zkServer.sh start

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

[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]

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

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

$ rm -rf /data/logs/zookeeper/*
$ rm -rf /data/zookeeper/*

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

server.1=nn01:2888:3888
server.2=nn02:2888:3888
server.3=dn01:2888:3888
server.4=dn02:2888:3888
server.5=dn03:2888:3888

ZooKeeper 会自动根据这里的配置把所有的节点连接成一个集群。
接着,把所有其他节点都装上 ZooKeeper 并配置好,最后一并启动起来。

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

$ jps
3249 QuorumPeerMain
3283 Jps

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

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

这个步骤是可选的,可以不做,但是添加自启动脚本是一个好习惯,免得重启之后完全忘记之前是怎么启动这些服务的了。我经常重启服务器,如果不设定自启动脚本,那么,每次都需要把启动服务的那些命令都敲一遍,非常费时。
用 root 账户在 /etc/init.d 下建立一个文件叫 zookeeper ,内容如下(请自行替换 JAVA_HOME 变量为你机器的 JDK 所在目录路径)。

注:下面的脚本只适用于CentOS及一下版本

#!/bin/bash
#chkconfig:2345 80 10
#description: zookeeper service
RETVAL=0
export JAVA_HOME="/usr/local/jdk1.7.0_79"
start() {
    su zookeeper -c "/usr/local/zookeeper/bin/zkServer.sh start"
}
stop() {
    su zookeeper -c "/usr/local/zookeeper/bin/zkServer.sh stop"
}
case $1 in
start)
    start
;;
stop)
    stop
;;
esac
exit $RETVAL

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

$ chmod +x zookeeper

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

# service zookeeper start

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

# chkconfig zookeeper on

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

4.4 配置 Hadoop HA

接下来我们要为 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 节点的操作。

4.4.1 JournalNode

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

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

java.io.IOException: Tied out waiting 20000ms for a quorum of nodes to respond.

然后就自杀了:

/**********************************************************
SHUTDOWN_MSG: Shutting down NameNode at 50/0.0.0.50
**********************************************************/

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

<property>
    <name>dfs.qjournal.start-segment.timout.ms</name>
    <value>60000</value>
</property>

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

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:

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

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

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

<property>
    <name>dfs.ha.namenodes.mycluster</name>
    <value>nn01,nn02</value>
</property>

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

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

<property>
    <name>dfs.namenode.rpc-address.mycluster.nn01</name>
    <value>nn01:8020</value>
</property>
<property>
    <name>dfs.namenode.rpc-address.mycluster.nn02</name>
    <value>nn02:8020</value>
</property>

STEP 4 配置 namenode 的 http 访问地址

<property>
    <name>dfs.namenode.http-address.mycluster.nn01</name>
    <value>nn01:50070</value>
</property>
<property>
    <name>dfs.namenode.http-address.mycluster.nn02</name>
    <value>nn02:50070</value>
</property>

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

<property>
    <name>dfs.namenode.shared.edits.dir</name>
    <value>qjournal://nn01:8485;nn02:8485;dn01:8485;dn02:8485;dn03:8485/mycluster</value>
</property>

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

STEP 6 配置dfs客户端

dfs客户端的作用是判断哪个 namenode 是活跃的,我们现在要配置 dfs 客户端的 Java 类名。
目前就一个实现,除非你要自己定义一个类,否则照着这个配置写就对了:

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

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

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

<property>
    <name>dfs.ha.fencing.methods</name>
    <value>sshfence</value>
</property>
<property>
    <name>dfs.ha.fencing.ssh.private-key-files</name>
    <value>/home/hadoop/.ssh/id_rsa</value>
</property>

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

<property>
    <name>dfs.journalnode.edits.dir</name>
    <value>/data/hadoop/hdfs/jn</value>
</property>

2. core-site.xml
修改 core-site.xml 文件。
将之前的 fs.defaultFS 从:

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

换成:

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

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

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

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

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

# mkdir /data/hadoop/hdfs/jn
# chown hadoop.hadoop /data/hadoop/hdfs/jn

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

$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh start journalnode

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

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

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

startng journalnode, logging to 
/data/logs/hadoop/hadoop-hadoop-journalnode-50.out

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

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

$ hdfs namenode -format

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

$ hdfs namenode -bootstrapStandby

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

$ hdfs namenode -initializeSharedEdits

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

$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --script hdfs start namenode

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

6. 执行手动failover
手动failover即手动切换namenode。手动切换可以用haadmin命令。由于我有两个namenode:nn01 和 nn02,因此我要把nn01切换为激活(active)状态,需要执行的命令如下:

hdfs haadmin -failover nn02 nn01

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

Failover from nn02 to nn01 successful

这个时候我们再去看nn01的控制台,我们就可以看到,nn01的状态已经被成功地切换成active了。

4.4.3 脑裂现象

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

4.4.4 zkcf

Hadoop zkfc用于自动检测namenode是否宕机。

zkfc好行不是那么稳定
在使用skfc的时候,你会发现在硬件条件不那么好的情况下,zkfc不稳定。
你会发现zkfc一般都是超过5s连不上ZooKeeper就自动退出了。为了解决此类问题,我们需要提高 ha.zookeeper.session-timeout.ms的设置(在试验环境中设置它为30000)。我们可以在core-site.xml中加入这段配置:

<property>
    <name>ha.zookeeper.session-timeout.ms</name>
    <value>30000</value>
</property>

4.4.5 配置自动failover

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

按以下步骤配置自动failover:

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

<property>
    <name>DFS.HA.AUTOMATIC-FAILOVER.ENABLED</name>
    <value>TRUE</value>
</property>

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

<property>
    <name>ha.zookeeper.quorum</name>
    <value>nn01:2181;nn02:2181;dn01:2181;dn02:2181;dn03:2181</value>
</property>

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

$ $HADOOP_PREFIX/bin/hdfs zkfc -formatZK

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

[zk: localhost:2181(CONNECTED) 1] ls /
[hadoop-ha, zookeeper]

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

(4) 我们来把 namenode 都停掉,再启动起来,让它们都进入 standby 状态。
再两台机器上都停止 namenode:

$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --script hdfs stop namenode

然后启动 namenode:

$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --script hdfs start namenode

启动之后通过浏览器访问

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

$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --script $HADOOP_PREFIX/bin/hdfs start zkfc

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

$ jps
26004 Jps
9249 JournalNode
25717 NameNode
25941 DFSZKFailoverController

(6) 验证自动failover。
打开浏览器访问两个 namenode 的控制台

然后在进行接下来的操作之前,请先关闭整个Hadoop集群。

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

# rm -rf /data/hadoop/hdfs/dn/*

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

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

猜你喜欢

转载自www.cnblogs.com/zifeiy/p/9338002.html