在安裝HBase的時候需要配置一些參數(shù),這些參數(shù)在HBase啟動的時候發(fā)揮著怎樣的作用颖系,如何影響的HBase的運行嗅剖,出現(xiàn)啟動錯誤時如何快速定位錯誤的位置。在解決這些問題之前嘁扼,先從源碼的角度分析一下HBase的啟動流程信粮,了解HBase是怎么啟動的。
啟動流程概述
啟動HBase會執(zhí)行start-hbase.sh偷拔,然后腳本會先執(zhí)行hbase-config.sh蒋院,做一系列的配置設(shè)置,包括常用路徑莲绰、regionservers和backup-masters列表、常用端口等姑丑。在hbase-config.sh中會執(zhí)行hbase-env.sh蛤签,主要對JAVA的環(huán)境參數(shù)、ssh,栅哀、pid路徑等進行配置震肮。start-hbase.sh最后會根據(jù)hbase.cluster.distributed來確定啟動模式,分為本地和分布式留拾。
分布式啟動HBase戳晌,使用hbase-daemons.sh逐步啟動zookeeper、master痴柔、regionserver沦偎、master-backup。具體會調(diào)用相關(guān)的腳本(如zookeeper會調(diào)用zookeerper.sh)來進行環(huán)境的配置和登錄到相關(guān)的機器節(jié)點上執(zhí)行hbase-daemon.sh咳蔚。
hbase-daemon.sh的職責(zé)就是啟動各個進程豪嚎,在啟動過程中會先做進程判斷,日志滾動等準(zhǔn)備谈火,最后執(zhí)行啟動命名侈询,逐步的啟動各個節(jié)點上的進程。在啟動過程中糯耍,會在屏幕中打印啟動信息扔字。
執(zhí)行流程圖:
具體啟動流程
接下來分析每一步的源碼囊嘉,了解整個執(zhí)行的過程。
start-hbase.sh
作為HBase啟動的入口革为,在執(zhí)行hbase-config.sh設(shè)置完運行的環(huán)境變量后扭粱,會執(zhí)行命令,獲取hbase.cluster.distributed的值來確定HBase的啟動模式篷角。
distMode=`$bin/hbase --config "$HBASE_CONF_DIR" org.apache.hadoop.hbase.util.HBaseConfTool hbase.cluster.distributed | head -n 1`
具體的代碼實現(xiàn):
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-backup
fi
standalone模式將會在一個JVM中運行所有的HBase和zookeeper嘉蕾。distributed模式會逐漸啟動zookeeper贺奠、master、regionserver错忱、master-backup等進程和節(jié)點儡率。在啟動節(jié)點時,$commandToRun有兩種選擇以清,可以是start(默認)儿普,還可以是autorestart。
hbase-config.sh
由于啟動的腳本如hbase-daemon.sh掷倔,zookeerper.sh等都不是在一臺機器上運行眉孩,因此每個腳本在執(zhí)行前都會先執(zhí)行一下hbase-config.sh來配置運行時的環(huán)境變量。
在hbase-config.sh中首先會檢查hbase-config.sh是否是一個軟連接勒葱,找到hbase-config.sh的真實路徑浪汪。然后設(shè)置HBASE_HOME,判斷是否指定了hbase的配置文件路徑凛虽,如果沒有將采用默認的配置文件路徑死遭。
腳本會設(shè)置一些默認的參數(shù),包括HBASE_CONF_DIR凯旋、HBASE_REGIONSERVERS呀潭、HBASE_BACKUP_MASTERS、HBASE_THRIFT_JMX_OPTS等瓦阐,然后執(zhí)行hbase-env.sh配置HBase的AVA的運行環(huán)境和ssh參數(shù)等蜗侈。程序會判斷是否設(shè)置HBASE_REGIONSERVER_MLOCK為true,這個主要是判斷系統(tǒng)是否使用了mlock來鎖住內(nèi)存睡蟋,防止這段內(nèi)存被操作系統(tǒng)swap掉踏幻。這將阻止Linux 將這個內(nèi)存頁調(diào)度到交換空間(swap space),即使該程序已有一段時間沒有訪問這段空間戳杀。最后如果檢測到了JAVA_HOME后该面,程序?qū)^續(xù)運行夭苗。
hbase-env.sh
hbase-env.sh中設(shè)置了HBase運行中的一些重要的JVM參數(shù),后續(xù)在進行HBase調(diào)優(yōu)時會用到這些參數(shù)隔缀。除此之外還有一些進程優(yōu)先級题造,SSH參數(shù)等。主要參數(shù)如下:
1猾瘸、JAVA_HOME
JAVA的JDK路徑界赔,需要java 1.7以上
2、HBASE_HEAPSIZE
堆的最大使用量牵触。默認情況下是JVM默認值
3淮悼、HBASE_OFFHEAPSIZE
如果打算使用堆緩存,可以設(shè)置該值揽思。例如袜腥,要分配8G的offheap,將值設(shè)置為“8G”钉汗。
4羹令、HBASE_OPTS
默認為"-XX:+UseConcMarkSweepGC"
使用CMS收集器對年老代進行垃圾收集,CMS收集器通過多線程并發(fā)進行垃圾回收损痰,盡量減少垃圾收集造成的停頓福侈。
5、PermSize設(shè)置非堆內(nèi)存初始值
僅僅是JDK7需要配置卢未,JDK8+后就不需要
6癌刽、HBASE_MASTER_OPTS、HBASE_REGIONSERVER_OPTS
配置非堆內(nèi)存尝丐,初始分配的堆內(nèi)存,大允許分配的堆內(nèi)存衡奥,按需分配
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中的文件易失守伸,導(dǎo)致找不到pid文件绎秒,最后配置一個其它穩(wěn)定的文件。
10尼摹、HBASE_NICENESS
守護進程的調(diào)度優(yōu)先級
11见芹、HBASE_IDENT_STRING
標(biāo)志hbase實例的字符串剂娄,默認情況下為當(dāng)前用戶,會在創(chuàng)建pid玄呛,log等文件時使用
12阅懦、HBASE_BACKUP_MASTERS
在backup-masters中配置配置bakcup的master,當(dāng)一臺master宕機后徘铝,zookeeper會在backup中選擇一個耳胎。默認backup-masters是不存在的,需要自己新建
13惕它、HBASE_SSH_OPTS
ssh配置怕午,如果ssh的端口不是22,可以進行設(shè)置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比較簡單揭北,主要根據(jù)要啟動的進程扳炬,生成好遠程執(zhí)行命令remote_cmd,然后做分發(fā)搔体。
remote_cmd="cd ${HBASE_HOME}; $bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} $@"
args="--hosts ${HBASE_REGIONSERVERS} --config ${HBASE_CONF_DIR} $remote_cmd"
command=$2
case $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:,,'`
# 獲取執(zhí)行命令,從hbase-daemons.sh傳過來
# remote_cmd="cd ${HBASE_HOME}; $bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} $@"
cmd=$"${@// /\\ }"
for zookeeper in $hosts; do
# 登錄到節(jié)點上
ssh $HBASE_SSH_OPTS $zookeeper $cmd 2>&1 | sed "s/^/$zookeeper: /" &
if [ "$HBASE_SLAVE_SLEEP" != "" ]; then
# 等待
sleep $HBASE_SLAVE_SLEEP
fi
done
fi
wait
在org.apache.hadoop.hbase.zookeeper.ZKServerTool
中通過readZKNodes獲取到zookeerper的節(jié)點地址呆奕。
其會在conf目錄下搜尋zoo.cfg文件养晋,加載zookeeper的配置,如果沒有則會去hbase-site.xml中加載zookeeper的配置梁钾,包括hbase.zookeeper.quorum绳泉,hbase.zookeeper.property.clientPort,hbase.zookeeper.property.dataDir等參數(shù)姆泻。因此zookeeper的信息可以在zoo.cfg中配置零酪,也可以在hbase-site.xml中進行配置。
master-backup.sh
在master-backup.sh中拇勃,首先會獲取到 backup-masters列表四苇,然后登陸到節(jié)點上去以backup的方式啟動master
HOSTLIST=$HBASE_BACKUP_MASTERS
# 獲取backup-masters列表,在hbase-env.sh中設(shè)置HBASE_BACKUP_MASTERS參數(shù)
if [ "$HOSTLIST" = "" ]; then
if [ "$HBASE_BACKUP_MASTERS" = "" ]; then
export HOSTLIST="${HBASE_CONF_DIR}/backup-masters"
else
export HOSTLIST="${HBASE_BACKUP_MASTERS}"
fi
fi
args=${@// /\\ }
args=${args/master-backup/master}
if [ -f $HOSTLIST ]; then
for hmaster in `cat "$HOSTLIST"`; do
# 登錄到節(jié)點上 啟動backup master
ssh $HBASE_SSH_OPTS $hmaster $"$args --backup" \
2>&1 | sed "s/^/$hmaster: /" &
if [ "$HBASE_SLAVE_SLEEP" != "" ]; then
sleep $HBASE_SLAVE_SLEEP
fi
done
fi
啟動后zookeeper會自動選取一個master作為active方咆,其它的都是backup月腋。
regionservers.sh
首先獲取到regionservers列表,默認在conf/regionservers中進行設(shè)置,如果regionservers是默認的localhost罗售,則會在本地啟動regionserver辜窑。設(shè)置成distributed后,會在各個節(jié)點上啟動regionserver節(jié)點寨躁。$”${@// /\\ }“
會將命令中將所有的\替換成為空格穆碎。
HOSTLIST=$HBASE_REGIONSERVERS
# 獲取regionservers
if [ "$HOSTLIST" = "" ]; then
if [ "$HBASE_REGIONSERVERS" = "" ]; then
export HOSTLIST="${HBASE_CONF_DIR}/regionservers"
else
export HOSTLIST="${HBASE_REGIONSERVERS}"
fi
fi
regionservers=`cat "$HOSTLIST"`
# 本地模式
if [ "$regionservers" = "localhost" ]; then
"$bin"/local-regionservers.sh start 1
else
for regionserver in `cat "$HOSTLIST"`; do
# 并行執(zhí)行
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
done
fi
hbase-daemon.sh
前面的腳本都是做的準(zhǔn)備工作,啟動各個節(jié)點最后都是由hbase-daemon.sh來完成的职恳。因此hbase-daemon.sh應(yīng)該是最重要的腳本所禀,負責(zé)啟動前的環(huán)境清理,日志滾動以及進程啟動等工作放钦。
hbase-daemon.sh支持start|stop|restart|autorestart|foreground_start色徘,5種啟動方式,可以單獨用來管理節(jié)點操禀,如啟動regionserver:hbase-daemon.sh start regionserver
經(jīng)過一系列的日志文件路徑設(shè)置后褂策,開始執(zhí)行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檢查要啟動的進程是否存在颓屑,如果存在就會發(fā)出$command running as process cat $HBASE_PID. Stop it first
的提示斤寂。看到這個提示揪惦,應(yīng)該到該機器節(jié)點上去查詢一下該進程的情況遍搞。
check_before_start(){
#ckeck if the process is not running
mkdir -p "$HBASE_PID_DIR"
if [ -f $HBASE_PID ]; then
# kill -0 pid 不發(fā)送任何信號,但是系統(tǒng)會進行錯誤檢查,檢查一個進程是否存在器腋,存在返回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)
# 當(dāng)腳本收到SIGHUP SIGINT SIGTERM EXIT的信號時,trap命令執(zhí)行雙引號中的命令
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.
# 設(shè)置hbase節(jié)點進程執(zhí)行的優(yōu)先級
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
;;
當(dāng)腳本收到SIGHUP SIGINT SIGTERM EXIT的信號時驹饺,trap命令執(zhí)行cleanAfterRun钳枕,kill掉已經(jīng)存在的進程,然后告訴zk刪除有問題的節(jié)點赏壹。
# 當(dāng)運行遇到問題時進行清理
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刪除有問題的節(jié)點
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中將會進行一系列的設(shè)置如日志蝌借,lib庫昔瞧,執(zhí)行類等指蚁,最終會運行exec "$JAVA" -Dproc_$COMMAND -XX:OnOutOfMemoryError="kill -9 %p" $HEAP_SETTINGS $HBASE_OPTS $CLASS "$@"
來啟動相應(yīng)的進程。執(zhí)行成功后自晰,可以ps -ef|grep 進程名
來查看最后是執(zhí)行了什么命令來啟動進程的凝化,如查看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
總結(jié)
HBase在啟動過程中搓劫,會先配置大量的參數(shù),重要的有JVM參數(shù)混巧,regionserver枪向,master-backup列表,路徑等咧党。分析一遍啟動的過程后秘蛔,明白了哪些參數(shù)在什么位置使用,起到了什么樣的作用傍衡,能夠為HBase的運維提供一個指導(dǎo)深员。最后自己也學(xué)到了很多shell編程的知識。