前置知识
$0:这个程式的执行名字$n:这个程式的第n个参数,n=1...9$*:这个程式的所有参数,此选项参数可超过9个$#:这个程式的参数个数$$:这个程式的PID(脚本运行的当前进程ID号)$!:执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)$?:执行上一个指令的返回值(显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误)$-:显示shell使用的当前选项,与set命令功能相同@跟*类似,但是可以当做数组用
#!/bin/bashecho "######starting run service.sh######"# 下面判断程式如果没有参数,退出if [ $# -lt 1 ]; then echo "USAGE: $0 classname opts" exit 1fiBASE_DIR=$(dirname $0)LIB_DIR="$BASE_DIR/lib"CONF_DIR="$BASE_DIR/conf"#请输入应用名,注意不要有空格SERVICE_NAME="appname"if [ "$SERVICE_NAME" == "" ]; then echo "变量SERVICE_NAME值为空,有可能会影响程序停服和启服"fiif [ ! -d $LIB_DIR ]; then ## 本段适用于springboot打包的应用 JAR_PATH=`ls *.jar` KEYWORD="$JAR_PATH" PID_FILE="$BASE_DIR/../$JAR_PATH.pid"else echo "您的应用可能不属于springboot类型,如已自定义,请忽略此提示" ## 下面一段脚本适用于jar包打在工程目录lib文件夹的应用## #请填写关键词(main方法所在的类路径) KEYWORD="你的服务包名" PID_FILE="$BASE_DIR/../$SERVICE_NAME.pid"fi#请指定jdk版本JAVA_VERSION=1.8if [ "$JAVA_VERSION" ]; then JDK_PATH=/usr/local/jdk8else JDK_PATH=/usr/local/jdkfifunction test_java_version() { java_version=`$1/java -version 2>&1 |awk 'NR==1{print $3}' |sed 's/\''//g'` if [[ ! "$java_version" =~ "$JAVA_VERSION" ]]; then return 1 fi return 0}if [ -z "$JAVA_HOME" ]; then JAVA_HOME=$JDK_PATHfiif ! test_java_version "$JAVA_HOME/bin" ; then if [[ ! -d "$JDK_PATH" ]]; then echo "$JDK_PATH not exist!" exit 2 fi if test_java_version "$JDK_PATH/bin" ; then export JAVA_HOME="$JDK_PATH" else echo "java version not match" exit 3 fifiJAVA_HOME=$JDK_PATH#请设置应用的JVM环境参数,此处仅为参考,注意点:MaxMetaspaceSize是jdk1.8版本的参数,1.7的改成permsizeXMS=${JVM_XMS:-4g}XMX=${JVM_XMX:-4g}XMN=${JVM_XMN:-2g}JAVA_OPTS="$JAVA_OPTS -server -Xms$XMS -Xmx$XMX -Xmn$XMN -XX:MaxMetaspaceSize=512m -XX:SurvivorRatio=8"JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+ScavengeBeforeFullGC -XX:CMSScavengeBeforeRemark"JAVA_OPTS="$JAVA_OPTS -XX:DisableExplicitGC -XX:OmitStackTraceInFastThrow"JAVA_OPTS="$JAVA_OPTS -XX:PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -xloggc:${HOME}/service_gc_`date +%Y%m%d%H%M%S`.log"JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeadDumpPath=${HOME}/service_heap_dump_`date +%Y%m%d%H%M%S`.hprof"JAVA="$JAVA_HOME/bin/java"###skyWalking hook ine ###if [ ! -d $LIB_DIR ]; then ## 本段适用于springboot打包的uberjar应用 JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:./ext:./external" JAVA_OPTS="$JAVA_OPTS -jar" # only applies to springboot's uberjarelse ############################################################################################# ## 下面一段脚本适用于jar包打在工程根目录lib文件夹的应用 JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext::${LIB_DIR}" CLASSPATH=${BASE_DIR}/conf:${BASE_DIR}/lib/\* JAVA_OPTS="${JAVA_OPTS} -cp ${CLASSPATH}"fi## 设置起服停服检查最大时间设置startchecktimeM="120"stopchecktimeM="120"if [ "$startchecktimeM" == "" ]; then echo "起服时间默认最大是120s,也可以在模板自定义" startchecktimeM="120"fiif [ "$startchecktimeM" == "" ]; then echo "停服时间默认最大是120s,也可以在模板自定义" stopchecktimeM="120"fifunction startService() { local server_type="$1" getServicePID if [ $? -eq 0 ]; then echo "$SERVICE_NAME is already running."; RETVAL=0; return 0; fi echo -n "Starting $SERVICE_NAME..." startServiceProcess if [ $? -ne 0 ]; then RETVAL=1; echo "$SERVICE_NAME start failed,see nohup.log."; return 1; fi COUNT=0 if [ "$server_type" == "provider" ]; then the_result=1 while [ $COUNT -1t 1 ]; do #provider起服轮询时间最大值默认为120s for (( i = 0; i < $startchecktimeM; i++ )); do startPortCheck $pid if [ $? -ne 0 ]; then echo -e ".\c" sleep 1; else the_result=0 echo "start cost $i s" break; fi done break done else ## assuming standdalone dubbo server,we will check if the_result=1 while [ $COUNT -1t 1 ]; do # consume起服轮询时间最大值默认为120s for (( i = 0; i < $startchecktimeM; i++ )); do STR=`grep "server started" nohup.log` if [ ! -z "$STR" ]; then echo "PID=$pid" echo "Server start OK in $i seconds" the_result=0 break; fi echo -e ".\c" sleep 1 done break done fi echo $the_result RETVAL=$the_result if [ $the_result -eq 1 ]; then echo "The service is gone or port is unnormal,please check!" fi return $RETVAL;}function startServiceProcess() { touch $PID_FILE rm -rf nohup.log nohup $JAVA $JAVA_OPTS $KEYWORD >> nohup.log 2>&1 & echo $! > $PID_FILE sleep 1 pid="$(<$PID_FILE)" if checkProcessIsRunning $pid; then :; else echo "$SERVICE_NAME start failed,see nohup.log" return 1 fi return 0;}# return 0 if port is released successfully when startingfunction startPortCheck() { if [ ! -f $PID_FILE ]; then echo "Error:can't find $PID_FILE when starting port check!"; return 1; fi pid="$(<$PID_FILE)" app_ports=`netstat -lntp 2> /dev/null|grep $pid |awk '{print $4}' |awk -F ':' '{print $NF}'` for m in ${app_ports} do echo "$SERVICE_NAME is ok and ports as $m" result=`/opt/nc/bin/nc -zw 2 127.0.0.1 $m | grep successd |wc -l` if [[ $result == 1 ]]; then echo "$m port check success" continue else break fi done if [[ $result == 1 ]]; then echo "please wait for some seconds,it's checking the status of dubbo service" return 0; fi echo "$SERVICE_NAME dubbo provider check fail" return 1;}#returns 0 if process with PID $1 id runningfunction checkProcessIsRunning() { local pid="$1" ps -ef | grep java | grep $pid | grep "$KEYWORD" | grep -q --binary -F java if [ $? -ne 0 ]; then echo "Process $pid is running or could not be found." return 1; fi return 0;}# Returns 0 when the service is running and sets the variable $pid to the PIDfunction getServicePID() { if [ ! -f $PID_FILE ]; then return 1; fi pid="$(<$PID_FILE)" checkProcessIsRunning $pid || return 1 return 0;}function stopService() { getServicePID if [ $? -ne 0 ]; then echo "$SERVICE_NAME is not running."; RETVAL=0; return 0; fi processcheck getPortFile if [ $? -ne 0 ]; then echo "can't find portFile." return 1; fi echo "Stopping $SERVICE_NAME..." stopServiceProcess if [ $? -ne 0 ]; then RETVAL=1; echo "failed." return 1; fi for (( i = 0; i < 10; i++ )); do portReleaseCheck if [ $? -ne 0 ]; then echo "the port is not released successfully" sleep 1 else echo "all ports are released successfully" return 0 break; fi done RETVAL=0 return 0;}function stopServiceProcess() { STOP_DATE=`date +%Y%m%d%H%M%S` kill $pid || return 1 # 停服最大时间默认为120s for (( i = 0; i < stopchecktimeM; i++ )); do checkProcessIsRunning $pid if [ $? -ne 0 ]; then rm -f $PID_FILE return 0 fi sleep 1 done echo "\n $SERVICE_NAME did not terminate within 120 seconds,sending SIGKILL..." kill -s KILL $pid local killWaitTime=15 for (( i = 0; i < 10; i++ )); do checkProcessIsRunning $pid if [ $? -ne 0 ]; then rm -f $PID_FILE return 0 fi sleep 1 done echo "Error: $SERVICE_NAME could not be stopped within 120 + 10 seconds!" return 1;}function getPortFile() { port=`netstat -lntp 2> /dev/null |egrep -w "$pid\/" |awk '{print $4}' |awk -F ":" '{print $NF}'` if [ $? -ne 0 ]; then echo "WARNING: can't find service port when getPortFile" return 1; fi echo $port return 0;}#进程数目以及起服账号检查function processcheck() { piduser=`ps -ef | grep $pid | awk '{print $1}'` pidnum=`ps -ef | grep $pid | grep java | awk '{print $2}'` echo -e "=============================piduser=$piduser pidnum=$pidnum================\n" if [ "$piduser" == "root" ]; then echo -e "WARNING: process using root,please contact SCM!\n" exit -1; fi}#return 0 if all ports are released successfully when stoppingfunction portReleaseCheck() { sleep 3 port_check_result=0 for n in $port;do echo "port as $n,wait to release" port_check=`netstat -nltup 2> /dev/null | awk '{print $4}' | awk -F ":" '{if ($NF == "'$n''")print $NF}' | sort -u` echo "the number of unreleased ports:$port_check" if [[ $prot_check -eq 0 ]]; then echo "this port:$n is released successfully" else echo "this port is not released" port_check_result=1 return 1 fi done return 0;}function checkServiceStatus() { echo -n "checking for $SERVICE_NAME:" if getServicePID; then echo "running PID=$pid" RETVAL=0 else echo "stopped" RETVAL=3 fi return 0;}function main() { RETVAL=0 case "$1" in start) startService "$2" ;; stop) stopService ;; restart) stopService && startService "$2" ;; status) checkServiceStatus ;; *) echo "Usage: $0 {start|stop|restart|status} {provider}" exit 1 ;; esac exit $RETVAL}main "$1" "$2"