前置知识

  1. $0:这个程式的执行名字
  2. $n:这个程式的第n个参数,n=1...9
  3. $*:这个程式的所有参数,此选项参数可超过9
  4. $#:这个程式的参数个数
  5. $$:这个程式的PID(脚本运行的当前进程ID号)
  6. $!:执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)
  7. $?:执行上一个指令的返回值(显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误)
  8. $-:显示shell使用的当前选项,与set命令功能相同
  9. @跟*类似,但是可以当做数组用
  1. #!/bin/bash
  2. echo "######starting run service.sh######"
  3. # 下面判断程式如果没有参数,退出
  4. if [ $# -lt 1 ]; then
  5. echo "USAGE: $0 classname opts"
  6. exit 1
  7. fi
  8. BASE_DIR=$(dirname $0)
  9. LIB_DIR="$BASE_DIR/lib"
  10. CONF_DIR="$BASE_DIR/conf"
  11. #请输入应用名,注意不要有空格
  12. SERVICE_NAME="appname"
  13. if [ "$SERVICE_NAME" == "" ]; then
  14. echo "变量SERVICE_NAME值为空,有可能会影响程序停服和启服"
  15. fi
  16. if [ ! -d $LIB_DIR ]; then
  17. ## 本段适用于springboot打包的应用
  18. JAR_PATH=`ls *.jar`
  19. KEYWORD="$JAR_PATH"
  20. PID_FILE="$BASE_DIR/../$JAR_PATH.pid"
  21. else
  22. echo "您的应用可能不属于springboot类型,如已自定义,请忽略此提示"
  23. ## 下面一段脚本适用于jar包打在工程目录lib文件夹的应用##
  24. #请填写关键词(main方法所在的类路径)
  25. KEYWORD="你的服务包名"
  26. PID_FILE="$BASE_DIR/../$SERVICE_NAME.pid"
  27. fi
  28. #请指定jdk版本
  29. JAVA_VERSION=1.8
  30. if [ "$JAVA_VERSION" ]; then
  31. JDK_PATH=/usr/local/jdk8
  32. else
  33. JDK_PATH=/usr/local/jdk
  34. fi
  35. function test_java_version() {
  36. java_version=`$1/java -version 2>&1 |awk 'NR==1{print $3}' |sed 's/\''//g'`
  37. if [[ ! "$java_version" =~ "$JAVA_VERSION" ]]; then
  38. return 1
  39. fi
  40. return 0
  41. }
  42. if [ -z "$JAVA_HOME" ]; then
  43. JAVA_HOME=$JDK_PATH
  44. fi
  45. if ! test_java_version "$JAVA_HOME/bin" ; then
  46. if [[ ! -d "$JDK_PATH" ]]; then
  47. echo "$JDK_PATH not exist!"
  48. exit 2
  49. fi
  50. if test_java_version "$JDK_PATH/bin" ; then
  51. export JAVA_HOME="$JDK_PATH"
  52. else
  53. echo "java version not match"
  54. exit 3
  55. fi
  56. fi
  57. JAVA_HOME=$JDK_PATH
  58. #请设置应用的JVM环境参数,此处仅为参考,注意点:MaxMetaspaceSize是jdk1.8版本的参数,1.7的改成permsize
  59. XMS=${JVM_XMS:-4g}
  60. XMX=${JVM_XMX:-4g}
  61. XMN=${JVM_XMN:-2g}
  62. JAVA_OPTS="$JAVA_OPTS -server -Xms$XMS -Xmx$XMX -Xmn$XMN -XX:MaxMetaspaceSize=512m -XX:SurvivorRatio=8"
  63. JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+ScavengeBeforeFullGC -XX:CMSScavengeBeforeRemark"
  64. JAVA_OPTS="$JAVA_OPTS -XX:DisableExplicitGC -XX:OmitStackTraceInFastThrow"
  65. JAVA_OPTS="$JAVA_OPTS -XX:PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -xloggc:${HOME}/service_gc_`date +%Y%m%d%H%M%S`.log"
  66. JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeadDumpPath=${HOME}/service_heap_dump_`date +%Y%m%d%H%M%S`.hprof"
  67. JAVA="$JAVA_HOME/bin/java"
  68. ###skyWalking hook ine ###
  69. if [ ! -d $LIB_DIR ]; then
  70. ## 本段适用于springboot打包的uberjar应用
  71. JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:./ext:./external"
  72. JAVA_OPTS="$JAVA_OPTS -jar" # only applies to springboot's uberjar
  73. else
  74. #############################################################################################
  75. ## 下面一段脚本适用于jar包打在工程根目录lib文件夹的应用
  76. JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext::${LIB_DIR}"
  77. CLASSPATH=${BASE_DIR}/conf:${BASE_DIR}/lib/\*
  78. JAVA_OPTS="${JAVA_OPTS} -cp ${CLASSPATH}"
  79. fi
  80. ## 设置起服停服检查最大时间设置
  81. startchecktimeM="120"
  82. stopchecktimeM="120"
  83. if [ "$startchecktimeM" == "" ]; then
  84. echo "起服时间默认最大是120s,也可以在模板自定义"
  85. startchecktimeM="120"
  86. fi
  87. if [ "$startchecktimeM" == "" ]; then
  88. echo "停服时间默认最大是120s,也可以在模板自定义"
  89. stopchecktimeM="120"
  90. fi
  91. function startService() {
  92. local server_type="$1"
  93. getServicePID
  94. if [ $? -eq 0 ]; then echo "$SERVICE_NAME is already running."; RETVAL=0; return 0; fi
  95. echo -n "Starting $SERVICE_NAME..."
  96. startServiceProcess
  97. if [ $? -ne 0 ]; then RETVAL=1; echo "$SERVICE_NAME start failed,see nohup.log."; return 1; fi
  98. COUNT=0
  99. if [ "$server_type" == "provider" ]; then
  100. the_result=1
  101. while [ $COUNT -1t 1 ]; do
  102. #provider起服轮询时间最大值默认为120s
  103. for (( i = 0; i < $startchecktimeM; i++ )); do
  104. startPortCheck $pid
  105. if [ $? -ne 0 ]; then
  106. echo -e ".\c"
  107. sleep 1;
  108. else
  109. the_result=0
  110. echo "start cost $i s"
  111. break;
  112. fi
  113. done
  114. break
  115. done
  116. else
  117. ## assuming standdalone dubbo server,we will check if
  118. the_result=1
  119. while [ $COUNT -1t 1 ]; do
  120. # consume起服轮询时间最大值默认为120s
  121. for (( i = 0; i < $startchecktimeM; i++ )); do
  122. STR=`grep "server started" nohup.log`
  123. if [ ! -z "$STR" ]; then
  124. echo "PID=$pid"
  125. echo "Server start OK in $i seconds"
  126. the_result=0
  127. break;
  128. fi
  129. echo -e ".\c"
  130. sleep 1
  131. done
  132. break
  133. done
  134. fi
  135. echo $the_result
  136. RETVAL=$the_result
  137. if [ $the_result -eq 1 ]; then echo "The service is gone or port is unnormal,please check!" fi
  138. return $RETVAL;
  139. }
  140. function startServiceProcess() {
  141. touch $PID_FILE
  142. rm -rf nohup.log
  143. nohup $JAVA $JAVA_OPTS $KEYWORD >> nohup.log 2>&1 & echo $! > $PID_FILE
  144. sleep 1
  145. pid="$(<$PID_FILE)"
  146. if checkProcessIsRunning $pid; then :; else
  147. echo "$SERVICE_NAME start failed,see nohup.log"
  148. return 1
  149. fi
  150. return 0;
  151. }
  152. # return 0 if port is released successfully when starting
  153. function startPortCheck() {
  154. if [ ! -f $PID_FILE ]; then
  155. echo "Error:can't find $PID_FILE when starting port check!";
  156. return 1;
  157. fi
  158. pid="$(<$PID_FILE)"
  159. app_ports=`netstat -lntp 2> /dev/null|grep $pid |awk '{print $4}' |awk -F ':' '{print $NF}'`
  160. for m in ${app_ports}
  161. do
  162. echo "$SERVICE_NAME is ok and ports as $m"
  163. result=`/opt/nc/bin/nc -zw 2 127.0.0.1 $m | grep successd |wc -l`
  164. if [[ $result == 1 ]]; then
  165. echo "$m port check success"
  166. continue
  167. else
  168. break
  169. fi
  170. done
  171. if [[ $result == 1 ]]; then
  172. echo "please wait for some seconds,it's checking the status of dubbo service"
  173. return 0;
  174. fi
  175. echo "$SERVICE_NAME dubbo provider check fail"
  176. return 1;
  177. }
  178. #returns 0 if process with PID $1 id running
  179. function checkProcessIsRunning() {
  180. local pid="$1"
  181. ps -ef | grep java | grep $pid | grep "$KEYWORD" | grep -q --binary -F java
  182. if [ $? -ne 0 ]; then
  183. echo "Process $pid is running or could not be found."
  184. return 1;
  185. fi
  186. return 0;
  187. }
  188. # Returns 0 when the service is running and sets the variable $pid to the PID
  189. function getServicePID() {
  190. if [ ! -f $PID_FILE ]; then
  191. return 1;
  192. fi
  193. pid="$(<$PID_FILE)"
  194. checkProcessIsRunning $pid || return 1
  195. return 0;
  196. }
  197. function stopService() {
  198. getServicePID
  199. if [ $? -ne 0 ]; then
  200. echo "$SERVICE_NAME is not running.";
  201. RETVAL=0;
  202. return 0;
  203. fi
  204. processcheck
  205. getPortFile
  206. if [ $? -ne 0 ]; then
  207. echo "can't find portFile."
  208. return 1;
  209. fi
  210. echo "Stopping $SERVICE_NAME..."
  211. stopServiceProcess
  212. if [ $? -ne 0 ]; then
  213. RETVAL=1;
  214. echo "failed."
  215. return 1;
  216. fi
  217. for (( i = 0; i < 10; i++ )); do
  218. portReleaseCheck
  219. if [ $? -ne 0 ]; then
  220. echo "the port is not released successfully"
  221. sleep 1
  222. else
  223. echo "all ports are released successfully"
  224. return 0
  225. break;
  226. fi
  227. done
  228. RETVAL=0
  229. return 0;
  230. }
  231. function stopServiceProcess() {
  232. STOP_DATE=`date +%Y%m%d%H%M%S`
  233. kill $pid || return 1
  234. # 停服最大时间默认为120s
  235. for (( i = 0; i < stopchecktimeM; i++ )); do
  236. checkProcessIsRunning $pid
  237. if [ $? -ne 0 ]; then
  238. rm -f $PID_FILE
  239. return 0
  240. fi
  241. sleep 1
  242. done
  243. echo "\n $SERVICE_NAME did not terminate within 120 seconds,sending SIGKILL..."
  244. kill -s KILL $pid
  245. local killWaitTime=15
  246. for (( i = 0; i < 10; i++ )); do
  247. checkProcessIsRunning $pid
  248. if [ $? -ne 0 ]; then
  249. rm -f $PID_FILE
  250. return 0
  251. fi
  252. sleep 1
  253. done
  254. echo "Error: $SERVICE_NAME could not be stopped within 120 + 10 seconds!"
  255. return 1;
  256. }
  257. function getPortFile() {
  258. port=`netstat -lntp 2> /dev/null |egrep -w "$pid\/" |awk '{print $4}' |awk -F ":" '{print $NF}'`
  259. if [ $? -ne 0 ]; then
  260. echo "WARNING: can't find service port when getPortFile"
  261. return 1;
  262. fi
  263. echo $port
  264. return 0;
  265. }
  266. #进程数目以及起服账号检查
  267. function processcheck() {
  268. piduser=`ps -ef | grep $pid | awk '{print $1}'`
  269. pidnum=`ps -ef | grep $pid | grep java | awk '{print $2}'`
  270. echo -e "=============================piduser=$piduser pidnum=$pidnum================\n"
  271. if [ "$piduser" == "root" ]; then
  272. echo -e "WARNING: process using root,please contact SCM!\n"
  273. exit -1;
  274. fi
  275. }
  276. #return 0 if all ports are released successfully when stopping
  277. function portReleaseCheck() {
  278. sleep 3
  279. port_check_result=0
  280. for n in $port;do
  281. echo "port as $n,wait to release"
  282. port_check=`netstat -nltup 2> /dev/null | awk '{print $4}' | awk -F ":" '{if ($NF == "'$n''")print $NF}' | sort -u`
  283. echo "the number of unreleased ports:$port_check"
  284. if [[ $prot_check -eq 0 ]]; then
  285. echo "this port:$n is released successfully"
  286. else
  287. echo "this port is not released"
  288. port_check_result=1
  289. return 1
  290. fi
  291. done
  292. return 0;
  293. }
  294. function checkServiceStatus() {
  295. echo -n "checking for $SERVICE_NAME:"
  296. if getServicePID; then
  297. echo "running PID=$pid"
  298. RETVAL=0
  299. else
  300. echo "stopped"
  301. RETVAL=3
  302. fi
  303. return 0;
  304. }
  305. function main() {
  306. RETVAL=0
  307. case "$1" in
  308. start)
  309. startService "$2"
  310. ;;
  311. stop)
  312. stopService
  313. ;;
  314. restart)
  315. stopService && startService "$2"
  316. ;;
  317. status)
  318. checkServiceStatus
  319. ;;
  320. *)
  321. echo "Usage: $0 {start|stop|restart|status} {provider}"
  322. exit 1
  323. ;;
  324. esac
  325. exit $RETVAL
  326. }
  327. main "$1" "$2"