简介
在Centos 6.5 下hadoop2.5.2的HA集群原理讲解以及详细配置(手动切换) 一文中讲述了如何搭建一个通过手工方式实现namenode HA机制,本文描述如同通过Zookeeper来实现自动的HA.
基本原理以及部分参数的讲解可参考手动切换的章节
硬件环境
HOSTNAME | IP | Hadoop | Zookeeper |
hadoop01 | 192.168.40.242 | NN,JN | ZKS |
hadoop02 | 192.168.40.243 | NN,JN | ZKS |
hadoop03 | 192.168.40.244 | DN,JN | ZKS |
hadoop04 | 192.168.40.245 | DN |
|
hadoop05 | 192.168.40.246 | DN |
|
基础环境配置
系统以及SSH配置请参考Centos 6.5 下hadoop2.5.2的HA集群原理讲解以及详细配置(手动切换)
Zookeeper
Zookeeper 的配置请参考:在CentOS上安装ZooKeeper集群
配置完后将三个Zks启动起来
配置
安装jdk
编辑在每台机器上配置/etc/profile文件,添加以下内容
export HADOOP_HOME=/root/hadoop/hadoop-2.5.2
export JAVA_HOME=/root/hadoop/jdk1.7.0_51
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
hadoop-env.sh
export JAVA_HOME=/root/hadoop/jdk1.7.0_51
core-site.xml
<configuration>
<!-- 指定namenode的主机名和端口号,此处的端口号需要和hdfs-size.xml的dfs.namenode.rpc-address配置的端口相同 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://cluster1</value>
<description>The name of the default file system.</description>
</property>
<!-- 配置hadoop的临时目录,我们需要把这个目录创建出来mkdir -p data/tmp ,这里的路径默认是NameNode,DataNode,JournalNode等存放数据的公共目录-->
<property>
<name>hadoop.tmp.dir</name>
<value>/data/hadoop/tmp</value>
<description>A base for other temporary directories.</description>
</property>
<!-- 这里是Zookeeper集群的地址和端口,注意一定要是奇数,并且数量不要少于三个节点 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop01:50090</value>
<description>
The secondary namenode http server address and port.
</description>
</property>
<!-- 配置web UI 访问hdfs系统的地址-->
<property>
<name>dfs.namenode.http-address</name>
<value>hadoop01:50070</value>
<description>
The address and the base port where the dfs namenode web ui will listen on.
</description>
</property>
<!-- 设置HDFS的副本数 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!-- 这一个最好去掉,开发时用,设置访问的权限,默认是true,就是检查权限,只有一个用户可以创建文件或目录,修改为所有用户都可以创建文件或目录 -->
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
<!-- 镜像文件存储的目录 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>file:///data/dfs/nn/name</value>
</property>
<!-- 编辑日志存储的目录 -->
<property>
<name>dfs.namenode.edits.dir</name>
<value>file:///data/dfs/nn/edits</value>
</property>
<!--dataName在本地的目录 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///data/dfs/dn</value>
</property>
<!--合并镜像文件的目录 -->
<property>
<name>dfs.namenode.checkpoint.dir</name>
<value>file:///data/dfs/snn/name</value>
</property>
<!--合并编辑日志的目录 -->
<property>
<name>dfs.namenode.checkpoint.edits.dir</name>
<value>file:///data/dfs/snn/edits</value>
</property>
<!--下面是配置HA -->
<!--集群中命名服务列表(自定义),使用Federation时,使用了1个HDFS集群。这里抽象出1个NameService实际上就是给这1个HDFS集群起了个别名。名字可以随便起,相互不重复即可-->
<property>
<name>dfs.nameservices</name>
<value>cluster1</value>
</property>
<!--命名服务中的namenode逻辑名称(自定义)-->
<property>
<name>dfs.ha.namenodes.cluster1</name>
<value>hadoop01,hadoop02</value>
</property>
<!--命名服务中逻辑名称对应的RPC地址-->
<property>
<name>dfs.namenode.rpc-address.cluster1.hadoop01</name>
<value>hadoop01:9000</value>
</property>
<property>
<name>dfs.namenode.rpc-address.cluster1.hadoop02</name>
<value>hadoop02:9000</value>
</property>
<!--命名服务中逻辑名称对应的HTTP地址-->
<property>
<name>dfs.namenode.http-address.cluster1.hadoop01</name>
<value>hadoop01:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.cluster1.hadoop02</name>
<value>hadoop02:50070</value>
</property>
<!--Journal Node数据存放目录,指定JournalNode集群在对NameNode的目录进行共享时,自己存储数据的磁盘路径-->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/data/journal/</value>
</property>
<!--主备NameNode同步元信息的共享存储系统,使用的是JournalNode集群来维护-->
<!--指定cluster1的两个NameNode共享edits文件目录时,使用的JournalNode集群信息-->
<!--下面是一个HDFS集群cluster1,所以有一个,如果有两个HDFS集群,每个NameNode对应NameService的配置文件-->
<!--修改cluster1-->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop01:8485;hadoop02:8485;hadoop03:8485/cluster1</value>
</property>
<!--是否启用了自动故障转移-->
<!--下面是一个HDFS集群cluster1,所以有一个,如果有两个HDFS集群,每个NameNode对应NameService的配置文件-->
<!--修改cluster1-->
<property>
<name>dfs.ha.automatic-failover.enabled.cluster1</name>
<value>true</value>
</property>
<!--指定cluster1出现故障时,有那个实现类负责执行故障切换-->
<!--下面是一个HDFS集群cluster1,所以有一个,如果有两个HDFS集群,每个NameNode对应NameService的配置文件-->
<!--修改cluster1-->
<property>
<name>dfs.client.failover.proxy.provider.cluster1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!--一旦需要NameNode切换,使用ssh方式进行操作 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<!-- 如果使用ssh进行故障切换,使用ssh通信时用的密钥存储的位置-->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
</configuration>
在上面的配置中有一个地方要特别说明一下,dfs.ha.fencing.ssh.private-key-files这里指向的是一个本地文件。上面我们是配置了两个namenode来实现HDFS的HA的,分别是nn1和nn2,在nn2的~/.ssh/目录下需要将nn1的~/.ssh/目录下的id_rsa文件copy过来,并且应该重命名成如id_rsa_nn1这样的文件名,以免覆盖了本地的文件。
yarn-site.xml
<configuration>
<!--Resourcemanager的配置,自定ResourceManager的地址,还是单点,这是隐患-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop01</value>
</property>
<!--配置resourcemanager的http地址 The http address of the RM web application.-->
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>hadoop01:8088</value>
</property>
<!--配置resourcemanager的https地址 The https adddress of the RM web application.-->
<property>
<name>yarn.resourcemanager.webapp.https.address</name>
<value>hadoop01:8090</value>
</property>
<!-- 在NM上还可以扩展自己的服务,yarn提供了一个yarn.nodemanager.aux-services的配置项,通过该配置,用户可以自定义一些服务,例如Map-Reduce的shuffle功能就是采用这种方式实现的 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
安装
- 然后在某一个namenode节点执行如下命令,创建命名空间
./bin/hdfs zkfc -formatZK - 在日志节点hadoop01,hadoop02,hadoop03用如下命令启日志程序
./sbin/hadoop-daemon.sh start journalnode - 在主namenode节点用./bin/hadoopnamenode -format格式化namenode和journalnode目录
./bin/hadoop namenode -format mycluster - 在主namenode节点启动./sbin/hadoop-daemon.shstart namenode进程
./sbin/hadoop-daemon.sh start namenode - 在备节点执行第一行命令,这个是把备namenode节点的目录格式化并把元数据从主namenode节点copy过来,并且这个命令不会把journalnode目录再格式化了!然后用第二个命令启动备namenode进程!
./bin/hdfs namenode –bootstrapStandby
./sbin/hadoop-daemon.sh start namenode - 在两个namenode节点都执行以下命令
./sbin/hadoop-daemon.sh start zkfc - 在所有datanode节点都执行以下命令启动datanode
./sbin/hadoop-daemon.sh start datanode - 下次启动的时候,就直接执行以下命令就可以全部启动所有进程和服务了:
./sbin/start-dfs.sh
验证
然后访问以下两个地址查看启动的两个namenode的状态:
http://hadoop01:50070/dfshealth.jsp 状态为:'hadoop01:9000' (active)
http://hadoop02:50070/dfshealth.jsp 状态为:'hadoop02:9000' (standby)
停止hdfs集群
停止所有HDFS相关的进程服务,执行以下命令:
./sbin/stop-dfs.sh
测试HDFS的HA功能
在任意一台namenode机器上通过jps命令查找到namenode的进程号,然后通过kill -9的方式杀掉进程,观察另一个namenode节点是否会从状态standby变成active状态。
$ jps
1686 JournalNode
1239 QuorumPeerMain
1380 NameNode
2365 Jps
1863 DFSZKFailoverController
$ kill -9 1380
然后观察原来是standby状态的namenode机器的zkfc日志,若最后一行出现如下日志,则表示切换成功:
2013-12-31 16:14:41,114 INFOorg.apache.hadoop.ha.ZKFailoverController: Successfully transitioned NameNodeat hadoop02/192.168.40.243:53310 to active state
这时再通过命令启动被kill掉的namenode进程
./sbin/hadoop-daemon.sh start namenode
对应进程的zkfc最后一行日志如下:
2013-12-31 16:14:55,683 INFOorg.apache.hadoop.ha.ZKFailoverController: Successfully transitioned NameNodeat hadoop01/192.168.40.242:53310 to standby state