在生产测试环境中,在使用脚本catalina.sh中止tomcat进程后失败,即时在catalina.sh脚本执行时加入-force参数也会失败,使用sh -x 分析catalina.sh脚本中止过程,将中止失败的地方抽取出来: java
+ FORCE=1 + '[' '!' -z '' ']' + /usr/java/jdk1.6.0_38/bin/java -server -Xms2048m -Xmx2048m -Xmn768m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+UseParallelOldGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/xrltest1/tomcat/dumpfile/heap.bin -Xloggc:/home/xrltest1/tomcat/logs/gc.log -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/xrltest1/tomcat/endorsed -classpath /home/xrltest1/tomcat/bin/bootstrap.jar -Dcatalina.base=/home/xrltest1/tomcat -Dcatalina.home=/home/xrltest1/tomcat -Djava.io.tmpdir=/home/xrltest1/tomcat/temp org.apache.catalina.startup.Bootstrap stop 2015-3-21 11:59:53 org.apache.catalina.startup.Catalina stopServer 严重: Catalina.stop: java.net.ConnectException: Connection refused at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) at java.net.Socket.connect(Socket.java:529) at java.net.Socket.connect(Socket.java:478) at java.net.Socket.<init>(Socket.java:375) at java.net.Socket.<init>(Socket.java:189) at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:422) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:338) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:416) + '[' '!' -z '' ']' + '[' 1 -eq 1 ']' + '[' -z '' ']' + echo 'Kill failed: $CATALINA_PID not set' Kill failed: $CATALINA_PID not set
从中能够看到,首先是执行java命令失败,没有中止tomcat,而后执行-force模块的命令,可是却没有找到$CATALINA_PID设定的进程号,咱们先不去关注java执行stop命令为何报错,而是看看为何加了-force参数也不起做用了 spring
为何没有$CATALINA_PID?接下来就带你们一探究竟 shell
首先,咱们将涉及到$CATALINA_PID变量的代码所有提取出来: apache
第一处: bootstrap
#如下这句判断设置的$CATALINA_PID变量若是不存在,则显示”Using CATALINA_PID: tomcat
$CATALINA_PID",若是存在则不显示 if [ ! -z "$CATALINA_PID" ]; then echo "Using CATALINA_PID: $CATALINA_PID" fi f
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMPDIR" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_OUT" 2>&1 & #从&能够看出启动的命令在后台启动 fi if [ ! -z "$CATALINA_PID" ]; then #判断CATALINA_PID若是不是空字符,则将Shell最后运行的后台Process的PID 传给$CATALINA_PID echo $! > "$CATALINA_PID" #在使用命令运行进程至后台时,可使用$!抓取前面启动运行在后台进程的进程号 fi fi #上面语句是tomcat在启动时,会将$CATALINA_PID写入PID进程号第三处:
if [ ! -z "$CATALINA_PID" ]; then #$CATALINA_PID文件不是非空 if [ -f "$CATALINA_PID" ]; then if [ -s "$CATALINA_PID" ]; then kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #kill -0 pid 不发送任何信号,可是系统会进行错误检查。 if [ $? -gt 0 ]; then echo "PID file found but no matching process was found. Stop aborted." exit 1 fi else echo "PID file is empty and has been ignored." fi else echo "\$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted." exit 1 fi fi
#若是发现$CATALINA_PID则发送一个模拟结束进程的型号,若是返回值为0,则正常,其余则异常,作退出操做 socket
#从上面的sh -x输出的信息对应的是:'[‘ ‘!’ -z ” ‘]’ 能够看出$CATALINA_PID变量没有设定,因此这个判断直接就结束了,什么都没作 测试
#下面的代码紧接着stop的正常中止代码下 if [ ! -z "$CATALINA_PID" ]; then #若是$CATALINA_PID不为空 if [ -f "$CATALINA_PID" ]; then #并且仍是普通文件 while [ $SLEEP -ge 0 ]; do #并且$SLEEP还大于0 kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #则测试下tomcat能不能被关闭 if [ $? -gt 0 ]; then #剩下的参数还有,则清空$CATALINA_PID rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then if [ -w "$CATALINA_PID" ]; then cat /dev/null > "$CATALINA_PID" else echo "Tomcat stopped but the PID file could not be removed or cleared." fi fi break fi if [ $SLEEP -gt 0 ]; then sleep 1 fi if [ $SLEEP -eq 0 ]; then if [ $FORCE -eq 0 ]; then echo "Tomcat did not stop in time. PID file was not removed." fi fi SLEEP=`expr $SLEEP - 1 ` done fi fi #上段语句主要是判断tomcat是否被关闭 #核心语句仍是:kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #while语句作sleep使用,用于清空$CATALINA_PID #可是[ ! -z "$CATALINA_PID" ]致使这段语句什么都没作啊!!!!!
d spa
#这段代码就是涉及-force的核心代码了 if [ $FORCE -eq 1 ]; then if [ -z "$CATALINA_PID" ]; then echo "Kill failed: \$CATALINA_PID not set" else if [ -f "$CATALINA_PID" ]; then PID=`cat "$CATALINA_PID"` echo "Killing Tomcat with the PID: $PID" kill -9 $PID #强制执行的核心命令 rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then echo "Tomcat was killed but the PID file could not be removed." fi fi fi fi #从中就能够看出,sh -x输出的Kill failed: $CATALINA_PID not set是怎么来的
总结下,$CATALINA_PID在整个代码中的做用: .net
1.在tomcat启动时会写入$CATALINA_PID,可是假设咱们的环境是多tomcat项目或$CATALINA_PID为空
2.stop代码中,检查$CATALINA_PID是否为空字符,是的话什么都不作
3.sstop代码中,检查$CATALINA_PID是否为空字符,是的话什么都不作
4.force代码中,检查$CATALINA_PID是否为空字符,是的话就报错
也就是说只要没有保存中这个项目的PID,那么正常stop中止不了,-force也是没有用的。
那么该如何解决呢?直接给$CATALINA_PID付PID的值,那么看结果:
+ FORCE=1 + '[' '!' -z 12031 ']' + '[' -f 12031 ']' + echo '$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted.' $CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted.涉及到的代码:
if [ -f "$CATALINA_PID" ]; then if [ -s "$CATALINA_PID" ]; then kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #kill -0 pid 不发送任何信号,可是系统会进行错误检查。 if [ $? -gt 0 ]; then echo "PID file found but no matching process was found. Stop aborted." exit 1 fi else echo "PID file is empty and has been ignored." fi else echo "\$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted." exit 1 #$CATALINA_PID不是个文件,因此很差意思,我退出了....
原来$CATALINA_PID还必须是个文件,那么咱们可不能够建这么一个文件呢?
在catalina.sh脚本的代码前,加入如下语句:
CATALINA_PID=/home/CATALINA_PID
若是tomcat启动时出现:
Existing PID file found during start.
Removing/clearing stale PID file.
说明生效了,可是若是项目中用了java.util.concurrent包里面的线程池,此方法无效,仍是不能关闭tomcat,关闭 tomcat时会出现Tomcat did not stop in time. PID file was not removed. To aid diagnostics a thread dump has been written to standard out,把线程池再改成spring管理便可