一例Linux上沒法中止tomcat分析及解決

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



第二處:(涉及到start參數的模塊內的$CATALINA_PID變量,只是提出來分析,其實不對stop模塊有影響)


-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管理便可

相關文章
相關標籤/搜索