HBase集群启动脚本流程分析

来源:互联网 发布:java apache 编辑:程序博客网 时间:2024/04/30 16:20

在安装HBase的时候需要配置一些参数,这些参数在HBase启动的时候发挥着怎样的作用,如何影响的HBase的运行,出现启动错误时如何快速定位错误的位置。在解决这些问题之前,先从源码的角度分析一下HBase的启动流程,了解HBase是怎么启动的。

启动流程概述

启动HBase会执行start-hbase.sh,然后脚本会先执行hbase-config.sh,做一系列的配置设置,包括常用路径、regionservers和backup-masters列表、常用端口等。在hbase-config.sh中会执行hbase-env.sh,主要对JAVA的环境参数、ssh,、pid路径等进行配置。start-hbase.sh最后会根据hbase.cluster.distributed来确定启动模式,分为本地和分布式。
分布式启动HBase,使用hbase-daemons.sh逐步启动zookeeper、master、regionserver、master-backup。具体会调用相关的脚本(如zookeeper会调用zookeerper.sh)来进行环境的配置和登录到相关的机器节点上执行hbase-daemon.sh。
hbase-daemon.sh的职责就是启动各个进程,在启动过程中会先做进程判断,日志滚动等准备,最后执行启动命名,逐步的启动各个节点上的进程。在启动过程中,会在屏幕中打印启动信息。
执行流程图:
这里写图片描述

具体启动流程

接下来分析每一步的源码,了解整个执行的过程。

start-hbase.sh

作为HBase启动的入口,在执行hbase-config.sh设置完运行的环境变量后,会执行命令,获取hbase.cluster.distributed的值来确定HBase的启动模式。

distMode=`$bin/hbase --config "$HBASE_CONF_DIR" org.apache.hadoop.hbase.util.HBaseConfTool hbase.cluster.distributed | head -n 1`

具体的代码实现:

hbase.cluster.distributed在hbase-site.xml中进行配置,默认值为false。false将启动standalone模式,true将启动distributed模式,在配置分布式的时候需要改成true。

if [ "$distMode" == 'false' ] then  "$bin"/hbase-daemon.sh --config "${HBASE_CONF_DIR}" $commandToRun master $@else  "$bin"/hbase-daemons.sh --config "${HBASE_CONF_DIR}" $commandToRun zookeeper  "$bin"/hbase-daemon.sh --config "${HBASE_CONF_DIR}" $commandToRun master   "$bin"/hbase-daemons.sh --config "${HBASE_CONF_DIR}" \    --hosts "${HBASE_REGIONSERVERS}" $commandToRun regionserver  "$bin"/hbase-daemons.sh --config "${HBASE_CONF_DIR}" \    --hosts "${HBASE_BACKUP_MASTERS}" $commandToRun master-backupfi

standalone模式将会在一个JVM中运行所有的HBase和zookeeper。distributed模式会逐渐启动zookeeper、master、regionserver、master-backup等进程和节点。在启动节点时,$commandToRun有两种选择,可以是start(默认),还可以是autorestart。

hbase-config.sh

由于启动的脚本如hbase-daemon.sh,zookeerper.sh等都不是在一台机器上运行,因此每个脚本在执行前都会先执行一下hbase-config.sh来配置运行时的环境变量。
在hbase-config.sh中首先会检查hbase-config.sh是否是一个软连接,找到hbase-config.sh的真实路径。然后设置HBASE_HOME,判断是否指定了hbase的配置文件路径,如果没有将采用默认的配置文件路径。
脚本会设置一些默认的参数,包括HBASE_CONF_DIR、HBASE_REGIONSERVERS、HBASE_BACKUP_MASTERS、HBASE_THRIFT_JMX_OPTS等,然后执行hbase-env.sh配置HBase的AVA的运行环境和ssh参数等。程序会判断是否设置HBASE_REGIONSERVER_MLOCK为true,这个主要是判断系统是否使用了mlock来锁住内存,防止这段内存被操作系统swap掉。这将阻止Linux 将这个内存页调度到交换空间(swap space),即使该程序已有一段时间没有访问这段空间。最后如果检测到了JAVA_HOME后,程序将会继续运行。

hbase-env.sh

hbase-env.sh中设置了HBase运行中的一些重要的JVM参数,后续在进行HBase调优时会用到这些参数。除此之外还有一些进程优先级,SSH参数等。主要参数如下:
1、JAVA_HOME
JAVA的JDK路径,需要java 1.7以上
2、HBASE_HEAPSIZE
堆的最大使用量。默认情况下是JVM默认值
3、HBASE_OFFHEAPSIZE
如果打算使用堆缓存,可以设置该值。例如,要分配8G的offheap,将值设置为“8G”。
4、HBASE_OPTS
默认为”-XX:+UseConcMarkSweepGC”
使用CMS收集器对年老代进行垃圾收集,CMS收集器通过多线程并发进行垃圾回收,尽量减少垃圾收集造成的停顿。
5、PermSize设置非堆内存初始值
仅仅是JDK7需要配置,JDK8+后就不需要
6、HBASE_MASTER_OPTS、HBASE_REGIONSERVER_OPTS
配置非堆内存,初始分配的堆内存,大允许分配的堆内存,按需分配
7、java回收机制,分别配置sever和client端
HBase会在启动的时候讲Java的一些配置打印到.out日志中

SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps"SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:<FILE-PATH>"SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:<FILE-PATH> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M"

8、HBASE_MANAGES_ZK
是否由它自己的zookpeer来管理,一般使用单独的zookeeper集群来管理hbase。
9、HBASE_PID_DIR
pid的路径,默认_tmp目录下,但_tmp中的文件易失,导致找不到pid文件,最后配置一个其它稳定的文件。
10、HBASE_NICENESS
守护进程的调度优先级
11、HBASE_IDENT_STRING
标志hbase实例的字符串,默认情况下为当前用户,会在创建pid,log等文件时使用
12、HBASE_BACKUP_MASTERS
在backup-masters中配置配置bakcup的master,当一台master宕机后,zookeeper会在backup中选择一个。默认backup-masters是不存在的,需要自己新建
13、HBASE_SSH_OPTS
ssh配置,如果ssh的端口不是22,可以进行设置HBASE_SSH_OPTS=”-p xxx”,后面再启动各个进程的时候会用到,如:

ssh $HBASE_SSH_OPTS $zookeeper $cmd 2>&1 | sed "s/^/$zookeeper: /" &

14、HBASE_LOG_DIR
hbase的日志路径

hbase-daemons.sh

hbase-daemons.sh比较简单,主要根据要启动的进程,生成好远程执行命令remote_cmd,然后做分发。

remote_cmd="cd ${HBASE_HOME}; $bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} $@"args="--hosts ${HBASE_REGIONSERVERS} --config ${HBASE_CONF_DIR} $remote_cmd"command=$2case $command in  (zookeeper)    exec "$bin/zookeepers.sh" $args    ;;  (master-backup)    exec "$bin/master-backup.sh" $args    ;;  (*)    exec "$bin/regionservers.sh" $args    ;;esac

zookeepers.sh

如果HBASE_MANAGES_ZK为true,表示hbase使用自带的zookeeper集群,如果不是,需要去加载用户自定义的配置。

if [ "$HBASE_MANAGES_ZK" = "true" ]; then  hosts=`"$bin"/hbase org.apache.hadoop.hbase.zookeeper.ZKServerTool | grep '^ZK host:' | sed 's,^ZK host:,,'`    # 获取执行命令,从hbase-daemons.sh传过来    # remote_cmd="cd ${HBASE_HOME}; $bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} $@"  cmd=$"${@// /\\ }"  for zookeeper in $hosts; do    # 登录到节点上   ssh $HBASE_SSH_OPTS $zookeeper $cmd 2>&1 | sed "s/^/$zookeeper: /" &   if [ "$HBASE_SLAVE_SLEEP" != "" ]; then    # 等待     sleep $HBASE_SLAVE_SLEEP   fi  donefiwait

org.apache.hadoop.hbase.zookeeper.ZKServerTool中通过readZKNodes获取到zookeerper的节点地址。
其会在conf目录下搜寻zoo.cfg文件,加载zookeeper的配置,如果没有则会去hbase-site.xml中加载zookeeper的配置,包括hbase.zookeeper.quorum,hbase.zookeeper.property.clientPort,hbase.zookeeper.property.dataDir等参数。因此zookeeper的信息可以在zoo.cfg中配置,也可以在hbase-site.xml中进行配置。

master-backup.sh

在master-backup.sh中,首先会获取到 backup-masters列表,然后登陆到节点上去以backup的方式启动master

HOSTLIST=$HBASE_BACKUP_MASTERS# 获取backup-masters列表,在hbase-env.sh中设置HBASE_BACKUP_MASTERS参数if [ "$HOSTLIST" = "" ]; then  if [ "$HBASE_BACKUP_MASTERS" = "" ]; then    export HOSTLIST="${HBASE_CONF_DIR}/backup-masters"  else    export HOSTLIST="${HBASE_BACKUP_MASTERS}"  fifiargs=${@// /\\ }args=${args/master-backup/master}if [ -f $HOSTLIST ]; then  for hmaster in `cat "$HOSTLIST"`; do    # 登录到节点上 启动backup master   ssh $HBASE_SSH_OPTS $hmaster $"$args --backup" \     2>&1 | sed "s/^/$hmaster: /" &   if [ "$HBASE_SLAVE_SLEEP" != "" ]; then     sleep $HBASE_SLAVE_SLEEP   fi  donefi 

启动后zookeeper会自动选取一个master作为active,其它的都是backup。

regionservers.sh

首先获取到regionservers列表,默认在conf/regionservers中进行设置,如果regionservers是默认的localhost,则会在本地启动regionserver。设置成distributed后,会在各个节点上启动regionserver节点。$”${@// /\\ }“会将命令中将所有的\替换成为空格。

HOSTLIST=$HBASE_REGIONSERVERS# 获取regionserversif [ "$HOSTLIST" = "" ]; then  if [ "$HBASE_REGIONSERVERS" = "" ]; then    export HOSTLIST="${HBASE_CONF_DIR}/regionservers"  else    export HOSTLIST="${HBASE_REGIONSERVERS}"  fifiregionservers=`cat "$HOSTLIST"`# 本地模式if [ "$regionservers" = "localhost" ]; then  "$bin"/local-regionservers.sh start 1else  for regionserver in `cat "$HOSTLIST"`; do    # 并行执行    if ${HBASE_SLAVE_PARALLEL:-true}; then      ssh $HBASE_SSH_OPTS $regionserver $"${@// /\\ }" \        2>&1 | sed "s/^/$regionserver: /" &    else # run each command serially      ssh $HBASE_SSH_OPTS $regionserver $"${@// /\\ }" \        2>&1 | sed "s/^/$regionserver: /"    fi    if [ "$HBASE_SLAVE_SLEEP" != "" ]; then      sleep $HBASE_SLAVE_SLEEP    fi  donefi

hbase-daemon.sh

前面的脚本都是做的准备工作,启动各个节点最后都是由hbase-daemon.sh来完成的。因此hbase-daemon.sh应该是最重要的脚本,负责启动前的环境清理,日志滚动以及进程启动等工作。
hbase-daemon.sh支持start|stop|restart|autorestart|foreground_start,5种启动方式,可以单独用来管理节点,如启动regionserver:hbase-daemon.sh start regionserver
经过一系列的日志文件路径设置后,开始执行start过程。

(start)    check_before_start    hbase_rotate_log $HBASE_LOGOUT    hbase_rotate_log $HBASE_LOGGC    # 启动进程    echo starting $command, logging to $HBASE_LOGOUT    $thiscmd --config "${HBASE_CONF_DIR}" \        foreground_start $command $args < /dev/null > ${HBASE_LOGOUT} 2>&1  &    disown -h -r    sleep 1; head "${HBASE_LOGOUT}"  ;;

首先check_before_start检查要启动的进程是否存在,如果存在就会发出$command running as process cat $HBASE_PID. Stop it first的提示。看到这个提示,应该到该机器节点上去查询一下该进程的情况。

check_before_start(){    #ckeck if the process is not running    mkdir -p "$HBASE_PID_DIR"    if [ -f $HBASE_PID ]; then    # kill -0 pid 不发送任何信号,但是系统会进行错误检查,检查一个进程是否存在,存在返回0;不存在返回1      if kill -0 `cat $HBASE_PID` > /dev/null 2>&1; then        echo $command running as process `cat $HBASE_PID`.  Stop it first.        exit 1      fi    fi}

接着进行日志的滚动,如果日志文件存在就进行1->5的滚动,因此我们能够看到logs下有编号1到5的日志文件。默认情况是不会输出GC日志的,可以在hbase-env.sh中开启SERVER_GC_OPTS,CLIENT_GC_OPTS配置,才会输出GC日志。

hbase_rotate_log (){    log=$1;    num=5;    if [ -n "$2" ]; then    num=$2    fi    # 检查日志文件是否存在,并做日志滚动    if [ -f "$log" ]; then # rotate logs      while [ $num -gt 1 ]; do          prev=`expr $num - 1`          [ -f "$log.$prev" ] && mv -f "$log.$prev" "$log.$num"          num=$prev      done      mv -f "$log" "$log.$num";    fi}

随后会使用foreground_start来启动进程

(foreground_start)    # 当脚本收到SIGHUP SIGINT SIGTERM EXIT的信号时,trap命令执行双引号中的命令    trap cleanAfterRun SIGHUP SIGINT SIGTERM EXIT    if [ "$HBASE_NO_REDIRECT_LOG" != "" ]; then        # NO REDIRECT        echo "`date` Starting $command on `hostname`"        echo "`ulimit -a`"        # in case the parent shell gets the kill make sure to trap signals.        # Only one will get called. Either the trap or the flow will go through.        # 设置hbase节点进程执行的优先级        nice -n $HBASE_NICENESS "$HBASE_HOME"/bin/hbase \            --config "${HBASE_CONF_DIR}" \            $command "$@" start &    else        echo "`date` Starting $command on `hostname`" >> ${HBASE_LOGLOG}        echo "`ulimit -a`" >> "$HBASE_LOGLOG" 2>&1        # in case the parent shell gets the kill make sure to trap signals.        # Only one will get called. Either the trap or the flow will go through.        nice -n $HBASE_NICENESS "$HBASE_HOME"/bin/hbase \            --config "${HBASE_CONF_DIR}" \            $command "$@" start >> ${HBASE_LOGOUT} 2>&1 &    fi    # Add to the command log file vital stats on our environment.    hbase_pid=$!    echo $hbase_pid > ${HBASE_PID}    wait $hbase_pid  ;;

当脚本收到SIGHUP SIGINT SIGTERM EXIT的信号时,trap命令执行cleanAfterRun,kill掉已经存在的进程,然后告诉zk删除有问题的节点。

# 当运行遇到问题时进行清理cleanAfterRun() {  if [ -f ${HBASE_PID} ]; then    # If the process is still running time to tear it down.    kill -9 `cat ${HBASE_PID}` > /dev/null 2>&1    rm -f ${HBASE_PID} > /dev/null 2>&1  fi  if [ -f ${HBASE_ZNODE_FILE} ]; then    if [ "$command" = "master" ]; then      HBASE_OPTS="$HBASE_OPTS $HBASE_MASTER_OPTS" $bin/hbase master clear > /dev/null 2>&1    else      #call ZK to delete the node      # 告诉zk删除有问题的节点      ZNODE=`cat ${HBASE_ZNODE_FILE}`      HBASE_OPTS="$HBASE_OPTS $HBASE_REGIONSERVER_OPTS" $bin/hbase zkcli delete ${ZNODE} > /dev/null 2>&1    fi    rm ${HBASE_ZNODE_FILE}  fi}

从代码中可以看到,最后启动脚本使用hbase命令来启动的,在hbase中将会进行一系列的设置如日志,lib库,执行类等,最终会运行exec "$JAVA" -Dproc_$COMMAND -XX:OnOutOfMemoryError="kill -9 %p" $HEAP_SETTINGS $HBASE_OPTS $CLASS "$@"来启动相应的进程。执行成功后,可以ps -ef|grep 进程名来查看最后是执行了什么命令来启动进程的,如查看HMaster如何启动的ps -ef|grep HMaster,就会列出具体的进程信息。

/usr/java/jdk1.8.0_65/bin/java -Dproc_master -XX:OnOutOfMemoryError=kill -9 %p -Xmx5G -XX:+UseConcMarkSweepGC -XX:PermSize=128m -XX:MaxPermSize=128m -Dhbase.log.dir=/home/xuxphp/hbase/logs -Dhbase.log.file=hbase-xuxphp-master-xuxp022.log -Dhbase.home.dir=/home/xuxphp/hbase -Dhbase.id.str=xuxphp -Dhbase.root.logger=INFO,RFA -Djava.library.path=/home/xuxphp/hadoop/lib/native -Dhbase.security.logger=INFO,RFAS org.apache.hadoop.hbase.master.HMaster start

总结

HBase在启动过程中,会先配置大量的参数,重要的有JVM参数,regionserver,master-backup列表,路径等。分析一遍启动的过程后,明白了哪些参数在什么位置使用,起到了什么样的作用,能够为HBase的运维提供一个指导。最后自己也学到了很多shell编程的知识。

原创粉丝点击