记一次生产发版时SpringBoot服务停用启用的问题

Posted linhui0705

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次生产发版时SpringBoot服务停用启用的问题相关的知识,希望对你有一定的参考价值。

近期项目交接,接手了个SpringBoot项目。生产环境里,jar包是通过软链接做成linux服务来启动和停用。

然而,每次通过jenkins构建发版,项目构建完毕,还要手动再去重启服务。

听交接的同事说,可能是有一个钩子阻止服务停用了。

但是,我还是有点纳闷的,既然阻止了服务停用,按道理服务是还能再运行的,不可能构建完了服务就不可用,然后还要手动重启。

随后,我就开始了漫长的搜索……最后还是找到答案了。


步骤重现:

jenkins构建项目,执行脚本,停用服务

service crm-base stop

等了大约一分钟,窗口返回:

Unable to kill process [*****]

脚本执行完停止命令,随后执行启动命令

Unable to kill process [*****]

结果提示,服务正在运行。

Already running [*****]

 

然而,过了一会儿,去访问服务接口时,服务没有响应了。去查Eureka,微服务的状态此时是Down。

查服务的状态

service crm-base status

结果服务是没有启动的

Not running


显然,执行了服务停止的命令是有效的,感觉是一段时间内服务没有停下来而提示“Unable to kill process”。

接下来,在看到了SpringBoot的内嵌启动脚本源码,也印证了我的想法。

stop() {
  working_dir=$(dirname "$jarfile")
  pushd "$working_dir" > /dev/null
  [[ -f $pid_file ]] || { echoYellow "Not running (pidfile not found)"; return 0; }
  pid=$(cat "$pid_file")
  isRunning "$pid" || { echoYellow "Not running (process ${pid}). Removing stale pid file."; rm -f "$pid_file"; return 0; }
  do_stop "$pid" "$pid_file"
}

do_stop() {
  kill "$1" &> /dev/null || { echoRed "Unable to kill process $1"; return 1; }
  for i in $(seq 1 $STOP_WAIT_TIME); do
    isRunning "$1" || { echoGreen "Stopped [$1]"; rm -f "$2"; return 0; }
    [[ $i -eq STOP_WAIT_TIME/2 ]] && kill "$1" &> /dev/null
    sleep 1
  done
  echoRed "Unable to kill process $1";
  return 1;
}

可以看到,执行停止方法,本质是做kill操作。方法内有一个for循环,从1遍历到$STOP_WAIT_TIME,每次循环休眠1秒。提示“Unable to kill process”有两处,一处是for循环前,一次是for循环后。

至于$STOP_WAIT_TIME的默认值是多少,我们用Ctrl+F搜脚本

# Initialize stop wait time if not provided by the config file
[[ -z "$STOP_WAIT_TIME" ]] && STOP_WAIT_TIME="{{stopWaitTime:60}}"

可以看到,如果没有配置设置停止等待时间,默认就是60秒。正好印证了这一问题,服务停止约一分钟就提示杀进程失败,而实际上是进程还在处理,需要等待,并非是钩子的问题。


解决方法:

在jar包路径下加jar包同名的配置文件(e.g.:jar包文件名为crm-base.jar,则添加配置的文件名称为crm-base.conf),在配置中调整停止等待时间为120秒

STOP_WAIT_TIME=120

再次尝试用jenkins构建,服务终于能顺利重启了。

开始关闭服务
-------------
Stopped [28032]
-------------
开始启动服务
Started [24119]

所以,遇到问题的时候,百度是能短时间解决同类问题,但是找不到解决方法的,还是通过阅读源码最可靠。


参考文档:

[1]. https://github.com/spring-projects/spring-boot/issues/4369

[2]. https://github.com/spring-projects/spring-boot/issues/10159

[3]. https://www.jianshu.com/p/e21b95006371

[4]. https://www.jianshu.com/p/1414dc49d3a9


以上是关于记一次生产发版时SpringBoot服务停用启用的问题的主要内容,如果未能解决你的问题,请参考以下文章

生产环境下多linux系统同时发包操作流程

记一次生产事故的排查与优化——Java服务假死

SpringBoot - 完全停用安全性以启用摘要转发

记一次生产环境thrift服务的配置问题

记一次线上FGC问题排查

记一次线上FGC问题排查