在生產測試環境中,在使用腳本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管理便可