为Hbase建立高可用性多主节点,hbase可用性主节点
为Hbase建立高可用性多主节点,hbase可用性主节点
Hadoop与HBase的设计中的从节点能够进行自动错误恢复。因为集群中存在大量的机器,所以很可能出现单台服务器的硬件错误或者单个从节点的异常。
至于主节点,HBase自身是不存在单点故障(Single Point of Failure – SPOF)的。HBase使用ZooKeerper作为中央控制服务。ZooKeeper用于三台以上的服务器集群之中,只要还有超过半数的服务器在线,ZooKeeper就能够正常提供服务。
HBase将活动主节点、域根节点服务器(root region server)地址以及其它重要的运行数据存放于ZooKeeper。因此,我们就可以在其它机器上开启两个或多个HMaster守护进程,其中第一个启动的HMaster作为HBase机器的活动主节点。
不过,HDFS的NameNode可能引起集群的单点故障。NameNode保存了HDFS全部文件系统的镜像在自己的本地存储之中。一旦NameNode异常,HDFS就无法使用了,导致HBase也无法使用。HDFS当中还有一个Secondary NameNode,它并不是一个备份NameNode,只是提供了一个NameNode的时间点保存镜像(checkpoint)。所以HBase集群的高可用性(highly available),实际上就是保持NameNode的高可用性。
本文中,我们将描述如何搭建两台高可用性的主节点,节点之间使用Heartbeat 互相探测。Heartbeat在Linux集群的HA的方案中被广泛使用,用于通讯与身份识别。Heartbeat 需要与集群资源管理(Cluster Resource Manager – CRM)绑定用于启动和停止集群服务。Heartbeat 推荐使用集群资源管理器Pacemaker来实现。我们将使用Heartbeat 和Pacemaker来搭建一个虚拟IP(Virtual IP – VIP)地址,然后将它与活动的主节点关联起来。因为EC2不支持静态IP,所以我们不能够在EC2上面实现上述方案,但我们将使用弹性IP(Elastic IP – EIP)来达到我们的目的。
我们主要着眼于建立NameNode和HBase,你也可以使用相似的方式来建立JobTracker节点。
准备
你应当已经安装好HDFS与HBase。我们需要使用一台已经准备好的机器建立一个备用的主节点(master2),确认所有的依赖都已经被正确的配置好了,将Hadoop与HBase的根目录从活动的主节点(master1)同步到备份节点上。
我们同样也需要NFS。搭建好NFS服务器,从 master1 和 master2 上挂载相同的NFS目录。确认hadoop用户在NFS目录中有写权限。在NFS中建立目录存储Hadoop的元信息(metadata)。我们假设该目录为/mnt/nfs/hadoop/dfs/name.
我们为两个主节点建立虚拟IP,假设IP地址与DNS映射如下:
- master1: IP地址为 10.174.14.11
- master2: IP地址为 10.174.14.12
- master: IP地址为 10.174.14.10稍后会设置为虚拟IP
如何实施
下面开始介绍如何建立两台高可用性主节点。
安装并配置Heartbeat 与Pacemaker
首先,我们安装Heartbeat 与Pacemaker,并且做一些配置
在 master1 and master2 上执行如下命令以安装Heartbeat 与Pacemaker(在centos 6.0 64x,使用yum可以安装,译者注):
root# apt-get install heartbeat cluster-glue cluster-agents pacemaker
在 master1 与master2 上对Heartbeat 进行如下配置:
root# vi /etc/ha.d/ha.cf
# enable pacemaker, without stonith # 开启pacemaker,不使用stonith # (译者注:STONITH这个名词为“Shoot The Other Node In The Head” . # STONITH的作用便是当宕机发生时,主要服务器可以藉此功能让备份服务器开机,以避免备份服务器启用浮动IP与相关服务, # 与主要服务器互抢控制权) crm yes # log where ? logfacility local0 # warning of soon be dead warntime 10 # declare a host (the other node) dead after: deadtime 20 # dead time on boot (could take some time until net is up) initdead 120 # time between heartbeats keepalive 2 # the nodes node master1 node master2 # heartbeats, over dedicated replication interface! ucast eth0 master1 # ignored by master1 (owner of ip) ucast eth0 master2 # ignored by master2 (owner of ip) # ping the name server to assure we are online ping ns
建立认证(authkeys )文件,在master1 与master2 上使用root用户执行下述脚本:
root# ( echo -ne “auth 1\n1 sha1 “; \
dd if=/dev/urandom bs=512 count=1 | openssl md5 ) \
> /etc/ha.d/authkeys
root# chmod 0600 /etc/ha.d/authkeys
创建并安装一个NameNode资源代理
Pacemaker 需要依靠资源代理来管理集群。在我们的例子中,虚拟IP和HDFS的NameNode服务就是希望用Pacemaker管理的集群资源。Pacemaker通过IP地址资源代理来管理虚拟IP,因此只需要建立NameNode的资源代理:
1 在 master1 和master2 的root用户下的 .bashrc 文件加入环境变量,别忘记在系统中应用这些变动:
root# vi /root/.bashrc
export JAVA_HOME=/usr/local/jdk1.6 export HADOOP_HOME=/usr/local/hadoop/current export OCF_ROOT=/usr/lib/ocf
执行如下命令来应用上述修改:
root# source /root/.bashrc
建立一个名为namenode的标准开放集群框架(Open Clustering Framework - OCF)资源代理文件。Namenode资源代理文件文件开头包含如下内容:
root# vi namenode
#!/bin/sh : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat} . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs usage() { echo "Usage: $0 {start|stop|status|monitor|meta-data|validate-all}" }
添加meta_data() 方法。该方法将资源代理的元数据导出到标准输出。每个资源代理都需要有一组对于自身目标以及支持参数的XML元数据描述:
root# vi namenode
meta_data() {cat <<END <?xml version="1.0"?> <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> <resource-agent name="namenode"> <version>0.1</version> <longdesc lang="en"> This is a resource agent for NameNode. It manages HDFS namenode daemon. </longdesc> <shortdesc lang="en">Manage namenode daemon.</shortdesc> <parameters></parameters> <actions> <action name="start" timeout="120" /> <action name="stop" timeout="120" /> <action name="status" depth="0" timeout="120" interval="120" /> <action name="monitor" depth="0" timeout="120" interval="120" /> <action name="meta-data" timeout="10" /> <action name="validate-all" timeout="5" /> </actions> </resource-agent> END }
添加namenode_start() 方法。Pacemaker使用这个方法在服务器上开启NameNode的守护进程。在这个方法中,我们检测NameNode是否已经启动,如果未启动,我们通过hadoop用户执行hadoop-daemon.sh 来启动:
root# vi namenode
namenode_start() { # if namenode is already started on this server, bail out early namenode_status if [ $? -eq 0 ]; then ocf_log info "namenode is already running on this server, skip" return $OCF_SUCCESS fi # start namenode on this server ocf_log info "Starting namenode daemon..." su - hadoop -c "${HADOOP_HOME}/bin/hadoop-daemon.sh start name node" if [ $? -ne 0 ]; then ocf_log err "Can not start namenode daemon." return $OCF_ERR_GENERIC; fi sleep 1 return $OCF_SUCCESS }
添加namenode_stop() 方法。Pacemaker使用这个方法停止服务器上的NameNode守护进程。在这个方法中,我们检查NameNode是否已经停止,如果尚未停止,我们通过hadoop用户执行hadoop-daemon.sh 来停止:
root# vi namenode
namenode_stop () { # if namenode is not started on this server, bail out early namenode_status if [ $? -ne 0 ]; then ocf_log info "namenode is not running on this server, skip" return $OCF_SUCCESS fi # stop namenode on this server ocf_log info "Stopping namenode daemon..." su - hadoop -c "${HADOOP_HOME}/bin/hadoop-daemon.sh stop name node" if [ $? -ne 0 ]; then ocf_log err "Can not stop namenode daemon." return $OCF_ERR_GENERIC; fi sleep 1 return $OCF_SUCCESS }
添加namenode_status() 方法。Pacemaker使用这个方法在服务器上检测NameNode守护进程的状态。在这个方法中,我们jps 命令来打印出 hadoop 用户所有运行的java进程,并使用grep 方法来过滤出NameNode守护进程来观察其是否正常启动:
root# vi namenode
namenode_status () { ocf_log info "monitor namenode" su - hadoop -c "${JAVA_HOME}/bin/jps" | egrep -q "NameNode" rc=$? # grep will return true if namenode is running on this machine if [ $rc -eq 0 ]; then ocf_log info "Namenode is running" return $OCF_SUCCESS else ocf_log info "Namenode is not running" return $OCF_NOT_RUNNING fi }
添加namenode_validateAll() 方法。确保在我们运行其它方法之前,所有的环境变量都已经被正确的设置了:
root# vi namenode
namenode_validateAll () { if [ -z "$JAVA_HOME" ]; then ocf_log err "JAVA_HOME not set." exit $OCF_ERR_INSTALLED fi if [ -z "$HADOOP_HOME" ]; then ocf_log err "HADOOP_HOME not set." exit $OCF_ERR_INSTALLED fi # Any subject is OK return $OCF_SUCCESS }
添加如下主例程。调用上述方法来实现必须的标准开放集群框架( OCF)代理动作:
root# vi namenode
# See how we were called. if [ $# -ne 1 ]; then usage exit $OCF_ERR_GENERIC fi namenode_validateAll case $1 in meta-data) meta_data exit $OCF_SUCCESS;; usage) usage exit $OCF_SUCCESS;; *);; esac case $1 in status|monitor) namenode_status;; start) namenode_start;; stop) namenode_stop;; validate-all);; *)usage exit $OCF_ERR_UNIMPLEMENTED;; esac exit $?
在 master1 和 master2 上修改namenode的文件权限:
root# chmod 0755 namenode root# ocf-tester -v -n namenode-test /full/path/of/namenode
2 确认在进入下一步之前,上述所有代码测试通过,否则高可用性集群可能会出现异常.
将namenode 资源代理安装到master1 和 master2 的 hac 目录之下:
root# mkdir ${OCF_ROOT}/resource.d/hac
root# cp namenode ${OCF_ROOT}/resource.d/hac
root# chmod 0755 ${OCF_ROOT}/resource.d/hac/namenode
配置高可用性的NameNode
我们已经通过Heartbeat 和 Pacemaker配置了高可用性的NameNode。接下来就是配置一个虚拟IP地址,Hadoop 和HBase使用该虚拟IP地址作为他们的主节点地址。虚拟IP首先指向活动的主节点,一旦主节点异常,Heartbeat 和 Pacemaker能够检测,并且将虚拟IP转换到备用主节点,然后在上面启动NameNode。
启动 master1 and master2 的Heartbeat :
root# /etc/init.d/heartbeat start
修改 crm 默认配置。master1 或 master2 的所有资源相关命令都只执行一次:
root# crm configure property stonith-enabled=false
root# crm configure property default-resource-stickiness=1
3 使用虚拟IP地址加入一个虚拟IP资源:
root# crm configure primitive VIP ocf:heartbeat:IPaddr params ip=”10.174.14.10″ op monitor interval=”10s”
4 修改Hadoop的配置,使用虚拟IP地址。在修改配置以后,同步配置文件到所有主节点、客户端和子节点:
hadoop$ vi $HADOOP_HOME/conf/core-site.xml
<property> <name>fs.default.name</name> <value>hdfs://master:8020</value> </property>
5 配置Hadoop将元信息同时写入本地与NFS,同步配置文件到所有主节点、客户端和子节点:
hadoop$ vi $HADOOP_HOME/conf/hdfs-site.xm
<property> <name>dfs.name.dir</name> <value>/usr/local/hadoop/var/dfs/name,/mnt/nfs/hadoop /dfs/name</value> </property>
6 将步骤5中创建的 namenode 资源代理加入到Pacemaker,我们将NAMENODE作为它的资源名称:
root# crm configure primitive NAMENODE ocf:hac:namenode op monitor interval=”120s” timeout=”120s” op start timeout=”120s” op stop timeout=”120s” meta resource-stickiness=”1″
7 将虚拟IP资源与NAMENODE资源配置为一个资源组:
root# crm configure group VIP-AND-NAMENODE VIP NAMENODE
8 为虚拟IP资源与NAMENODE资源定义托管(colocation):
root# crm configure colocation VIP-WITH-NAMENODE inf: VIP NAMENODE
9 为虚拟IP资源与NAMENODE资源定义资源排序
root# crm configure order IP-BEFORE-NAMENODE inf: VIP NAMENODE
10 使用crm_mon 命令来验证之前的Heartbeat与资源定义。若一切正常,应该看到如下输出:
root@master1 hac$ crm_mon -1r
============ Last updated: Tue Nov 22 22:39:11 2011 Stack: Heartbeat Current DC: master2 (7fd92a93-e071-4fcb-993f-9a84e6c7846f) - partition with quorum Version: 1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b 2 Nodes configured, 1 expected votes 1 Resources configured. ============ Online: [ master1 master2 ] Full list of resources: Resource Group: VIP-AND-NAMENODE VIP (ocf::heartbeat:IPaddr): Started master1 NAMENODE (ocf::hac:namenode): Started master1
11 确认虚拟IP资源与NAMENODE资源在同一台服务器上.
12 停止master1 的Heartbeat , 虚拟IP与NAMENOD 在数秒后在 master2 上启动.
13 重新启动master1 的Heartbeat,虚拟IP与NAMENOD 应当还是在 master2. 相关资源不应当回到 master1.
启动DataNode, HBase集群并备份HBase主节点(master)
确认了高可用性的配置正常工作之后,我们可以启动HDFS和HBase了。注意NameNode已经被Pacemaker启动了,所以我们只需要启动DataNode:
16 一切正常的话,启动DataNode:
hadoop@master$ for i in 1 2 3 do ssh slave$i "$HADOOP_HOME/bin/hadoop-daemon.sh start datanode" sleep 1 done
从虚拟IP指向的活动主节点(master1 )启动HBase集群:
hadoop@master$ $HBASE_HOME/bin/start-hbase.sh
启动备份节点(master2 )的HMaster进程:
hadoop@master2$ $HBASE_HOME/bin/hbase-daemon.sh start master
工作原理
下图描述了上述步骤执行完成后的集群架构:
首先,两台主节点上都安装了 Heartbeat 与 Pacemake,并配置了Heartbeat以支持Pacemaker。
在“创建并安装NameNode资源代理”章节的第2步,我们新建了一个实现标准OCF资源代理的namenode 脚本。其中最重要的部分就是namenode_status,它负责检测NameNode守护进程的状态。我们通过jps 命令来打印出 hadoop 用户所有运行的java进程,并使用grep 方法来过滤出NameNode守护进程来观察其是否正常启动。Pacemaker 使用namenode 资源代理来开启/关闭/监控NameNode守护进程。在namenode 的脚本中,namenode_start 和namenode_stop 是通过hadoop-daemon.sh 对单独服务器的Hadoop 守护进程启动和停止。你能够本文中找到相关源码。
当namenode 资源代理测试、安装完成并正常运行之后启动Heartbeat 。我们修改了一些 crm 的默认配置, default-resource-stickiness=1 非常重要,因为它关闭了资源的自动恢复。
在配置高可用性的NameNode一节中的第三到五步,我们在Pacemaker中添加了虚拟IP资源,并配置了Hadoop 和HBase。这样当活动主节点异常之后,可以切换至备用主节点。
同一章节的第六步,我们配置了Hadoop (HDFS NameNode)将元数据同时写入本地与NFS。若活动主节点异常,备用主节点会读取相同的NFS目录,启动NameNode,从而使用最新的元数据信息,在活动主节点异常之前恢复HDFS的状态。
在步骤7到10中,我们通过 namenode 资源代理构建了名为NAMENODE的资源,然后将 虚拟IP与NAMENOD 配置为一个资源组(步骤8),保证在同一服务器(步骤9),以正确顺序启动(步骤10)。这样可以保证不会出现虚拟IP指向master1,而NameNode在 master2 上面启动。
因为Pacemaker 会通过 namenode 资源代理启动NameNode,所以我们需要单独启动DataNode,也就是我们在步骤1中所做的内容:启动DataNode,HBase集群和HBase备份主节点。
HBase正常启动后,启动备份服务器上面的备份HBase主节点 (HMaster)。在备份服务器的日志中,可发现如下内容证明启动的是备份主节点 (HMaster):
2011-11-21 23:38:55,168 INFO org.apache.hadoop.hbase.master.ActiveMasterManager: Another master is the active master, ip-10-174-14-15.us-west-1.compute.internal:60000; waiting to become the next active master
最终NameNode 和HMaster在两台服务器上启动,并且可以随时进行异常切换,避免了集群中的单点异常。
然而,在生产环境实际运用还有很多问题需要处理。我们还要对高可用性集群进行各种特殊情况测试,如单台服务器断电、网线断开、交换机关闭或者能想到的其它任意情况。
另一方面来说,单点故障其实没有想象中那么严重。根据我们的经验,几乎所有的集群宕机都是因为异常操作或者软件升级,所以保持系统的简单性会让系统更稳定。
更多内容(Amzone EC2)
在 Amazon EC2 上建立高可用性的HBase集群更为复杂,因为EC2不支持静态IP地址,我们无法使用虚拟IP。可以考虑使用弹性IP(elastic-ip EIP)。在EC2中,弹性IP类似静态IP,弹性IP只是与你的账户关联,不是其它什么特殊实例。一旦活动主节点异常,我们可以使用Heartbeat自动关联弹性IP启动备份服务器。接着定义Hadoop和HBase使用与一个公共实例DNS关联的弹性IP来访问当前活动的主节点。在namenode 资源代理中,我们不但要启动或停止NameNode,而且还要处理所有的DataNode。因为活动主节点的IP变化了,DataNode必须重启之后才能访问新的主节点。
因为本文的范围有限,所以我们忽略掉一些细节。我们构建了一个弹性IP(elastic-ip EIP)资源代理来实现上述目的,相关源码在本文中可以找到。
英文原文:Safaribooksonline,编译:Wld5 - 陈晨
译文链接:http://www.wld5.com/3020.html
【如需转载,请在正文中标注并保留原文链接、译文链接和译者等信息,谢谢合作!】
用户点评