BIGTOP-732. Support running multiple HBase region servers
Project: http://git-wip-us.apache.org/repos/asf/bigtop/repo Commit: http://git-wip-us.apache.org/repos/asf/bigtop/commit/2fc2307c Tree: http://git-wip-us.apache.org/repos/asf/bigtop/tree/2fc2307c Diff: http://git-wip-us.apache.org/repos/asf/bigtop/diff/2fc2307c Branch: refs/heads/master Commit: 2fc2307c743250146d30a6a81b4f1581eac2076e Parents: a353721 Author: Sean Mackrory <[email protected]> Authored: Thu Apr 18 13:46:13 2013 -0700 Committer: Roman Shaposhnik <[email protected]> Committed: Wed May 1 17:51:57 2013 -0700 ---------------------------------------------------------------------- bigtop-packages/src/common/hbase/hbase.default | 7 + .../src/common/hbase/regionserver-init.d.tpl | 412 +++++++++++++++ .../src/deb/hbase/install_init_scripts.sh | 9 +- bigtop-packages/src/deb/hbase/rules | 4 +- bigtop-packages/src/rpm/hbase/SPECS/hbase.spec | 18 +- 5 files changed, 442 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/bigtop/blob/2fc2307c/bigtop-packages/src/common/hbase/hbase.default ---------------------------------------------------------------------- diff --git a/bigtop-packages/src/common/hbase/hbase.default b/bigtop-packages/src/common/hbase/hbase.default index 53dee46..3371a2b 100644 --- a/bigtop-packages/src/common/hbase/hbase.default +++ b/bigtop-packages/src/common/hbase/hbase.default @@ -17,3 +17,10 @@ export HBASE_PID_DIR="/var/run/hbase" export HBASE_LOG_DIR="/var/log/hbase" export HBASE_IDENT_STRING=hbase export HBASE_THRIFT_MODE="-nonblocking" + +# Up to 100 region servers can be run on a single host by specifying offsets +# here or as CLI args when using init scripts. Each offset identifies an +# instance and is used to determine the network ports it uses. Each instance +# will have have its own log and pid files. +# +# REGIONSERVER_OFFSETS="1 2 3" http://git-wip-us.apache.org/repos/asf/bigtop/blob/2fc2307c/bigtop-packages/src/common/hbase/regionserver-init.d.tpl ---------------------------------------------------------------------- diff --git a/bigtop-packages/src/common/hbase/regionserver-init.d.tpl b/bigtop-packages/src/common/hbase/regionserver-init.d.tpl new file mode 100644 index 0000000..8f45eb6 --- /dev/null +++ b/bigtop-packages/src/common/hbase/regionserver-init.d.tpl @@ -0,0 +1,412 @@ +#! /bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is used to run multiple instances of certain HBase daemons using init scripts. +# It replaces the local-regionserver.sh and local-master.sh scripts for Bigtop packages. +# By default, this script runs a single daemon normally. If offsets are provided, additional +# daemons are run, identified by the offset in log and pid files, and listening on the default +# port + the offset. Offsets can be provided as arguments when invoking init scripts directly: +# +# /etc/init.d/hbase-@HBASE_DAEMON@ start 1 2 3 4 +# +# or you can list the offsets to run in /etc/init.d/@HBASE_DAEMON@_offsets: +# +# echo "@HBASE_DAEMON@_OFFSETS='1 2 3 4' >> /etc/default/hbase" +# sudo service hbase-$HBASE_DAEMON@ start +# +# Offsets specified on the command-line always override the offsets file. If no offsets are +# specified on the command-line when stopping or restarting daemons, all running instances of the +# daemon are stopped (regardless of the contents of the offsets file). + +# chkconfig: @CHKCONFIG@ +# description: Summary: HBase is the Hadoop database. Use it when you need random, realtime read/write access to your Big Data. This project's goal is the hosting of very large tables -- billions of rows X millions of columns -- atop clusters of commodity hardware. +# processname: HBase +# +### BEGIN INIT INFO +# Provides: hbase-@HBASE_DAEMON@ +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $remote_fs +# Should-Start: $named +# Should-Stop: +# Default-Start: @INIT_DEFAULT_START@ +# Default-Stop: @INIT_DEFAULT_STOP@ +# Short-Description: Hadoop HBase @HBASE_DAEMON@ daemon +### END INIT INFO + +. /etc/default/hadoop +. /etc/default/hbase + +# Autodetect JAVA_HOME if not defined +. /usr/lib/bigtop-utils/bigtop-detect-javahome + +# Our default HBASE_HOME, HBASE_PID_DIR and HBASE_CONF_DIR +export HBASE_HOME=${HBASE_HOME:-/usr/lib/hbase} +export HBASE_PID_DIR=${HBASE_PID_DIR:-/var/run/hbase} +export HBASE_LOG_DIR=${HBASE_LOG_DIR:-/var/log/hbase} + +install -d -m 0755 -o hbase -g hbase ${HBASE_PID_DIR} + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON_SCRIPT=$HBASE_HOME/bin/hbase-daemon.sh +NAME=hbase-@HBASE_DAEMON@ +DESC="Hadoop HBase @HBASE_DAEMON@ daemon" +PID_FILE=$HBASE_PID_DIR/hbase-hbase-@[email protected] +CONF_DIR=/etc/hbase/conf + +DODTIME=3 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +UPPERCASE_HBASE_DAEMON=$(echo @HBASE_DAEMON@ | tr '[:lower:]' '[:upper:]') + +ALL_OFFSET_DAEMONS_RUNNING=0 +SOME_OFFSET_DAEMONS_FAILING=1 +NO_OFFSET_DAEMONS_RUNNING=2 +INVALID_OFFSETS_PROVIDED=3 + +# These limits are not easily configurable - they are enforced by HBase +if [ "@HBASE_DAEMON@" == "master" ] ; then + FIRST_PORT=60000 + FIRST_INFO_PORT=60010 + OFFSET_LIMIT=10 +elif [ "@HBASE_DAEMON@" == "regionserver" ] ; then + FIRST_PORT=60200 + FIRST_INFO_PORT=60300 + OFFSET_LIMIT=100 +fi + +validate_offsets() { + for OFFSET in $1; do + if [[ ! $OFFSET =~ ^((0)|([1-9][0-9]{0,2}))$ ]]; then + echo "ERROR: All offsets must be positive integers (no leading zeros, max $OFFSET_LIMIT)" + exit $INVALID_OFFSETS_PROVIDED + fi + if [ ${OFFSET} -lt 0 ] ; then + echo "ERROR: Cannot start @HBASE_DAEMON@ with negative offset" >&2 + exit $INVALID_OFFSETS_PROVIDED + fi + if [ ${OFFSET} -ge ${OFFSET_LIMIT} ] ; then + echo "ERROR: Cannot start @HBASE_DAEMON@ with offset higher than $OFFSET_LIMIT" >&2 + exit $INVALID_OFFSETS_PROVIDED + fi + done +} + +offset_pidfile() { + echo $HBASE_PID_DIR/hbase-hbase-$1-@[email protected] +} + +OFFSETS_FROM_CLI="${*:2}" +validate_offsets "$OFFSETS_FROM_CLI" +if [ -n "$(eval echo \${${UPPERCASE_HBASE_DAEMON}_OFFSETS})" ] ; then + OFFSETS_FROM_DEFAULT="$(eval echo \${${UPPERCASE_HBASE_DAEMON}_OFFSETS})" + validate_offsets "$OFFSETS_FROM_DEFAULT" +fi +OFFSET_PID_FILES="`ls $HBASE_PID_DIR/hbase-hbase-*-@[email protected] 2>/dev/null`" +if [ -n "$OFFSET_PID_FILES" ] ; then + OFFSETS_FROM_PIDS=`echo "$OFFSET_PID_FILES" | sed "s#$HBASE_PID_DIR/hbase-hbase-##" | sed "s#-.*##"` +fi + +multi_hbase_daemon_check_pidfiles() { + if [ -z "$OFFSETS_FROM_PIDS" ] ; then + return $NO_OFFSET_DAEMONS_RUNNING + fi + if [ -n "$OFFSETS_FROM_CLI" ] ; then + OFFSETS="$OFFSETS_FROM_CLI" + else + OFFSETS="$OFFSETS_FROM_PIDS" + fi + + RESULT=$ALL_OFFSET_DAEMONS_RUNNING + for OFFSET in $OFFSETS; do + echo -n "HBase @HBASE_DAEMON@ $OFFSET: " + if hbase_check_pidfile `offset_pidfile $OFFSET` ; then + echo "running" + else + echo "not running" + RESULT=$SOME_OFFSET_DAEMONS_FAILING + fi + done + return $RESULT +} + +multi_hbase_daemon_stop_pidfiles() { + if [ -z "$OFFSETS_FROM_PIDS" ] ; then + return $NO_OFFSET_DAEMONS_RUNNING + fi + if [ -n "$OFFSETS_FROM_CLI" ] ; then + OFFSETS="$OFFSETS_FROM_CLI" + else + OFFSETS="$OFFSETS_FROM_PIDS" + fi + + RESULT=$NO_OFFSET_DAEMONS_RUNNING + for OFFSET in $OFFSETS; do + echo -n "Forcefully stopping HBase @HBASE_DAEMON@ $OFFSET: " + PID_FILE=`offset_pidfile $OFFSET` + hbase_stop_pidfile $PID_FILE + if hbase_check_pidfile $PID_FILE ; then + echo "ERROR." + else + echo "OK." + rm -f $PID_FILE + fi + done + return $RESULT +} + +# Starts and stops multiple instances of HBase daemons +multi_hbase_daemon() { + COMMAND=$1 + OFFSETS="$OFFSETS_FROM_CLI" + if [ "$COMMAND" == "start" ] ; then + ACTION="Starting" + RUNNING="OK" + STOPPED="ERROR" + if [ -z "$OFFSETS_FROM_CLI" ] ; then + OFFSETS="$OFFSETS_FROM_DEFAULT" + fi + elif [ "$COMMAND" == "stop" ] ; then + ACTION="Stopping" + RUNNING="ERROR" + STOPPED="OK" + if [ -z "$OFFSETS_FROM_CLI" ] ; then + OFFSETS="$OFFSETS_FROM_PIDS" + fi + else + echo "ERROR: Illegal command: $COMMAND" + exit 1 + fi + + export HBASE_${UPPERCASE_HBASE_DAEMON}_OPTS=" " + + for OFFSET in ${OFFSETS} ; do + echo -n "$ACTION @HBASE_DAEMON@ daemon $OFFSET: " + export HBASE_IDENT_STRING="hbase-${OFFSET}" + LOG_FILE="$HBASE_LOG_DIR/hbase-$HBASE_IDENT_STRING-@HBASE_DAEMON@-$HOSTNAME.pid" + PID_FILE="$HBASE_PID_DIR/hbase-$HBASE_IDENT_STRING-@[email protected]" + HBASE_MULTI_ARGS="-D hbase.@[email protected]=`expr ${FIRST_PORT} + $OFFSET` \ + -D hbase.@[email protected]=`expr ${FIRST_INFO_PORT} + ${OFFSET}`" + hbase_check_pidfile $PID_FILE + STATUS=$? + if [[ "$STATUS" == "0" && "$COMMAND" == "start" ]] ; then + echo "Already running" + continue + elif [[ "$STATUS" != "0" && "$COMMAND" == "stop" ]] ; then + rm -f $PID_FILE + echo "Already stopped" + continue + fi + su -s /bin/bash hbase -c "${DAEMON_SCRIPT} ${COMMAND} regionserver ${HBASE_MULTI_ARGS} >> ${LOG_FILE}" + if [[ "$COMMAND" == "stop" ]] ; then + rm -f $PID_FILE + fi + if hbase_check_pidfile $PID_FILE ; then + echo "$RUNNING" + else + echo "$STOPPED" + fi + done + return 0 +} + +# Checks if the given pid represents a live process. +# Returns 0 if the pid is a live process, 1 otherwise +hbase_is_process_alive() { + local pid="$1" + ps -fp $pid | grep $pid | grep @HBASE_DAEMON@ > /dev/null 2>&1 +} + +# Check if the process associated to a pidfile is running. +# Return 0 if the pidfile exists and the process is running, 1 otherwise +hbase_check_pidfile() { + local pidfile="$1" # IN + local pid + + pid=`cat "$pidfile" 2>/dev/null` + if [ "$pid" = '' ]; then + # The file probably does not exist or is empty. + return 1 + fi + + set -- $pid + pid="$1" + + hbase_is_process_alive $pid +} + +# Kill the process associated to a pidfile +hbase_stop_pidfile() { + local pidfile="$1" # IN + local pid + + pid=`cat "$pidfile" 2>/dev/null` + if [ "$pid" = '' ]; then + # The file probably does not exist or is empty. Success + return 0 + fi + + set -- $pid + pid="$1" + + # First try the easy way + if hbase_process_kill "$pid" 15; then + rm $pidfile + return 0 + fi + + # Otherwise try the hard way + if hbase_process_kill "$pid" 9; then + rm $pidfile + return 0 + fi + + return 1 +} + +hbase_process_kill() { + local pid="$1" # IN + local signal="$2" # IN + local second + + kill -$signal $pid 2>/dev/null + + # Wait a bit to see if the dirty job has really been done + for second in 0 1 2 3 4 5 6 7 8 9 10; do + if hbase_is_process_alive "$pid"; then + # Success + return 0 + fi + + sleep 1 + done + + # Timeout + return 1 +} + +start() { + if [ -n "${OFFSETS_FROM_CLI}${OFFSETS_FROM_DEFAULT}" ] ; then + if hbase_check_pidfile $PID_FILE ; then + echo "$NAME has already been started - cannot start other @HBASE_DAEMON@ daemons." + exit 1 + fi + multi_hbase_daemon "start" + exit $? + fi + multi_hbase_daemon_check_pidfiles > /dev/null + if [ "$?" != "$NO_OFFSET_DAEMONS_RUNNING" ] ; then + echo "Cannot start $NAME - other @HBASE_DAEMON@ daemons have already been started." + exit 1 + fi + echo -n "Starting $DESC: " + su -s /bin/sh hbase -c "$DAEMON_SCRIPT start @HBASE_DAEMON@" + if hbase_check_pidfile $PID_FILE ; then + echo "$NAME." + else + echo "ERROR." + fi +} +stop() { + if [ -n "${OFFSETS_FROM_CLI}${OFFSETS_FROM_PIDS}" ] ; then + multi_hbase_daemon "stop" + return "$?" + fi + + echo -n "Stopping $DESC: " + su -s /bin/sh hbase -c "$DAEMON_SCRIPT stop @HBASE_DAEMON@" + if hbase_check_pidfile $PID_FILE ; then + echo "ERROR." + else + echo "$NAME." + fi +} + +force_stop() { + MULTI_HBASE_DAEMON_STATUS_TEXT=`multi_hbase_daemon_check_pidfiles` + MULTI_HBASE_DAEMON_STATUS=$? + if [ "$MULTI_HBASE_DAEMON_STATUS" == "$NO_OFFSET_DAEMONS_RUNNING" ] ; then + echo -n "Forcefully stopping $DESC: " + hbase_stop_pidfile $PID_FILE + if hbase_check_pidfile $PID_FILE ; then + echo " ERROR." + else + echo "$NAME." + fi + else + multi_hbase_daemon_stop_pidfiles + fi +} + +force_reload() { + # check wether $DAEMON is running. If so, restart + hbase_check_pidfile $PID_FILE && $0 restart $OFFSETS_FROM_CLI +} + +restart() { + echo -n "Restarting $DESC: " + stop + [ -n "$DODTIME" ] && sleep $DODTIME + $0 start $OFFSETS_FROM_CLI +} + +status() { + MULTI_HBASE_DAEMON_STATUS_TEXT=`multi_hbase_daemon_check_pidfiles` + MULTI_HBASE_DAEMON_STATUS=$? + if [ "$MULTI_HBASE_DAEMON_STATUS" == "$NO_OFFSET_DAEMONS_RUNNING" ] ; then + echo -n "$NAME is " + if hbase_check_pidfile $PID_FILE ; then + echo "running" + else + echo "not running." + exit 1 + fi + else + IFS='' + echo $MULTI_HBASE_DAEMON_STATUS_TEXT + exit $MULTI_HBAE_DAEMONS_STATUS + fi +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + force-stop) + force_stop + ;; + force-reload) + force_reload + ;; + restart) + restart + ;; + status) + status + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 + exit 1 + ;; +esac + +exit 0 http://git-wip-us.apache.org/repos/asf/bigtop/blob/2fc2307c/bigtop-packages/src/deb/hbase/install_init_scripts.sh ---------------------------------------------------------------------- diff --git a/bigtop-packages/src/deb/hbase/install_init_scripts.sh b/bigtop-packages/src/deb/hbase/install_init_scripts.sh index f60059c..1f3c151 100755 --- a/bigtop-packages/src/deb/hbase/install_init_scripts.sh +++ b/bigtop-packages/src/deb/hbase/install_init_scripts.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with @@ -27,6 +27,13 @@ for node in master regionserver rest thrift ; do service_pkgdir=debian/$SRC_PKG-$node debdir=$service_pkgdir/DEBIAN template="debian/service-init.d.tpl" + if [ "$node" == "regionserver" ] ; then + # Region servers start from a different template that allows + # them to run multiple concurrent instances of the daemon + template="debian/regionserver-init.d.tpl" + sed -i -e "s|@INIT_DEFAULT_START@|2 3 4 5|" $template + sed -i -e "s|@INIT_DEFAULT_STOP@|0 1 6|" $template + fi mkdir -p $service_pkgdir/etc/init.d/ $debdir sed -e "s|@HBASE_DAEMON@|$node|" -e "s|@CHKCONFIG@|$chkconfig|" $template > $service_pkgdir/etc/init.d/$SRC_PKG-$node http://git-wip-us.apache.org/repos/asf/bigtop/blob/2fc2307c/bigtop-packages/src/deb/hbase/rules ---------------------------------------------------------------------- diff --git a/bigtop-packages/src/deb/hbase/rules b/bigtop-packages/src/deb/hbase/rules index 9a6ddc8..9c8f68a 100755 --- a/bigtop-packages/src/deb/hbase/rules +++ b/bigtop-packages/src/deb/hbase/rules @@ -36,7 +36,7 @@ override_dh_auto_build: override_dh_auto_install: cp debian/hbase.default debian/${hbase_pkg_name}/etc/default/${hbase_pkg_name} - sh -x debian/install_hbase.sh \ + bash -x debian/install_hbase.sh \ --build-dir=build \ --conf-dir=/etc/hbase/conf.dist \ --doc-dir=usr/share/doc/${hbase_pkg_name}-doc \ @@ -56,4 +56,4 @@ override_dh_auto_install: find debian/tmp/usr/lib/${hbase_pkg_name}/bin debian/tmp/usr/lib/${hbase_pkg_name}/lib -name \*.rb -exec chmod 644 {} \; ### webapps should not be executable either find debian/tmp/usr/lib/${hbase_pkg_name}/hbase-webapps -type f -exec chmod 644 {} \; - sh debian/install_init_scripts.sh + bash debian/install_init_scripts.sh http://git-wip-us.apache.org/repos/asf/bigtop/blob/2fc2307c/bigtop-packages/src/rpm/hbase/SPECS/hbase.spec ---------------------------------------------------------------------- diff --git a/bigtop-packages/src/rpm/hbase/SPECS/hbase.spec b/bigtop-packages/src/rpm/hbase/SPECS/hbase.spec index d698bdf..ee15e4d 100644 --- a/bigtop-packages/src/rpm/hbase/SPECS/hbase.spec +++ b/bigtop-packages/src/rpm/hbase/SPECS/hbase.spec @@ -90,6 +90,7 @@ Source3: hbase.sh Source4: hbase.sh.suse Source5: hbase.default Source6: hbase.nofiles.conf +Source7: regionserver-init.d.tpl BuildArch: noarch Requires: coreutils, /usr/sbin/useradd, /sbin/chkconfig, /sbin/service Requires: hadoop-hdfs, zookeeper >= 3.3.1, bigtop-utils >= 0.6 @@ -273,11 +274,18 @@ do rest) chkconfig="345 88 12" ;; *) chkconfig="345 89 13" ;; esac - init_file=$RPM_BUILD_ROOT/%{initd_dir}/%{name}-${service} - %__cp $orig_init_file $init_file - %__sed -i -e "s|@CHKCONFIG@|${chkconfig}|" $init_file - %__sed -i -e "s|@HBASE_DAEMON@|${service}|" $init_file - chmod 755 $init_file + init_file=$RPM_BUILD_ROOT/%{initd_dir}/%{name}-${service} + %__cp $orig_init_file $init_file + if [[ "$service" = "regionserver" ]] ; then + # Region servers start from a different template that allows + # them to run multiple concurrent instances of the daemon + %__cp %{SOURCE7} $init_file + %__sed -i -e "s|@INIT_DEFAULT_START@|3 4 5|" $init_file + %__sed -i -e "s|@INIT_DEFAULT_STOP@|0 1 2 6|" $init_file + fi + %__sed -i -e "s|@CHKCONFIG@|${chkconfig}|" $init_file + %__sed -i -e "s|@HBASE_DAEMON@|${service}|" $init_file + chmod 755 $init_file done # FIXME: BIGTOP-648 workaround for HBASE-6263
