tomcat 在liunx中shutdown後進程仍然存在的兩種實用解決辦法

 方法一:html

查找tomcat進程並killjava

ps -elf | grep ${ctompath} | grep -v grep | awk '{print $4}' | xargs kill -9apache

此處可寫成腳本,可參考我以前的腳本 https://www.cnblogs.com/shenjianxin/p/9263765.htmlbootstrap

 

方法二:tomcat

修改$TOMCAT_HOME/bin/catalina.sh文件,PRGDIR下面一行添加CATALINA_PID參數行,修改完成後應該跟下面相同。socket

# Get standard environment variables PRGDIR=`dirname "$PRG"` CATALINA_PID=$PRGDIR/CATALINA_PID源碼分析

也能夠自定義pid路徑,例如「CATALINA_PID=/var/run/tomcat.pid」測試

 

要殺死進程須要添加參數 -force        ./shutdown.sh -force 或者 ./catalina.sh stop -forceui

 

 

 

源碼分析:(如下出處https://blog.csdn.net/hxyerui/article/details/52181884)spa

最近咱們在使用Jenkins自動化部署項目時,在生產liunx環境下,使用腳本shutdown.sh中止tomcat服務,而後再start以後發現應用沒法訪問了,後臺查看tomcat進程是發現有個2個tomcat進程,說明以前的shutdown並無徹底停掉tomcat進程。那怎麼樣tomcat使用shutdown以後立馬關掉其進程呢? 經查資料發如今shutdown.sh腳本以後有條命令是這樣的:

exec "$PRGDIR"/"$EXECUTABLE" stop "$@"

這個就是中止tomcat 服務的命令,咱們只須要加一個  -force  就能夠在shutdown時強制關閉tomcat進程

exec "$PRGDIR"/"$EXECUTABLE" stop -force "$@"

但光這樣仍是不行,再shutdown時報錯:

Kill failed: $CATALINA_PID not set

查找失敗緣由

  1. + FORCE=1
  2. + '[' '!' -z '' ']'
  3. + /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
  4. 2015-3-21 11:59:53 org.apache.catalina.startup.Catalina stopServer
  5. 嚴重: Catalina.stop:
  6. java.net.ConnectException: Connection refused
  7. at java.net.PlainSocketImpl.socketConnect(Native Method)
  8. at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
  9. at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
  10. at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
  11. at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
  12. at java.net.Socket.connect(Socket.java:529)
  13. at java.net.Socket.connect(Socket.java:478)
  14. at java.net.Socket.<init>(Socket.java:375)
  15. at java.net.Socket.<init>(Socket.java:189)
  16. at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:422)
  17. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  18. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  19. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  20. at java.lang.reflect.Method.invoke(Method.java:597)
  21. at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:338)
  22. at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:416)
  23. + '[' '!' -z '' ']'
  24. + '[' 1 -eq 1 ']'
  25. + '[' -z '' ']'
  26. + echo 'Kill failed: $CATALINA_PID not set'
  27. Kill failed: $CATALINA_PID not set

從中能夠看到,首先是執行java命令失敗,沒有中止tomcat,而後執行-force模塊的命令,可是卻沒有找到$CATALINA_PID設定的進程號,咱們先不去關注java執行stop命令爲何報錯,而是看看爲何加了-force參數也不起做用了

爲何沒有$CATALINA_PID?接下來就帶你們一探究竟

首先,咱們將涉及到$CATALINA_PID變量的代碼所有提取出來:

第一處:

#如下這句判斷設置的$CATALINA_PID變量若是不存在,則顯示"Using CATALINA_PID:

  1. $CATALINA_PID",若是存在則不顯示
  2. if [ ! -z "$CATALINA_PID" ]; then
  3. echo "Using CATALINA_PID: $CATALINA_PID"
  4. fi
  5. fi

#貌似只是判斷$CATALINA_PID是不是空字符,其餘什麼都沒有作

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

#這個是start模塊內的代碼 "$_RUNJAVA" "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS \ -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最後運行的後臺ProcessPID 傳給$CATALINA_PID echo $! > "$CATALINA_PID" #在使用命令運行進程至後臺時,可使用$!抓取前面啓動運行在後臺進程的進程號 fi fi #上面語句是tomcat在啓動時,會將$CATALINA_PID寫入PID進程號

第三處:

#一下語句都出如今stop模塊內 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,則正常,其餘則異常,作退出操做

#從上面的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" ]致使這段語句什麼都沒作啊!!!!!

第五處:

#這段代碼就是涉及-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在整個代碼中的做用:

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腳本的代碼前,加入如下語句:

######################################################################################### if [ -z "$CATALINA_PID" ]; then     CATALINA_PID=$PRGDIR/CATALINA_PID     cat $CATALINA_PID fi

######################################################################################

結果:tomcat中止執行成功,完成結束進程任務

總結:

在我看到的很到部署tomcat的文章中,還沒發現有關於設置$CATALINA_PID文件路徑的提示(也許是我看到的少),可是此處我要建議小夥伴們,在寫tomcat啓動、中止、重啓的腳本的時候,必定要注意這個變量。

相關文章
相關標籤/搜索