下午遇到一個神奇的問題:
secureCRT登陸某個服務器,用shell腳本啟動./catalina.sh start,打開日志tail -f catalina.out,此時 手動關閉連接窗口,導致tomcat的服務竟然關閉了,看日志,截圖如下:
仔細看圖,發現關鍵字:
AbstractProtocol pause、
org.apache.catalina.core.StandardService stopInternal
、DubboShutdownHook、EventThread shut down很明顯不是正常關閉打印的節奏。應該是觸發內核操作甚至還掛上了鈎子。上網一搜果然有問題:
shell腳本啟動tomcat,Tomcat啟動后,當前shell進程並沒有退出,而是掛住在tail進程,往終端輸出日志內容。這種情況下,如果用戶直接關閉ssh終端的窗口(用鼠標或快捷鍵),則java進程也會退出。而如果先ctrl-c
終止test.sh進程,然后再關閉ssh終端的話,則java進程不會退出。
腳本簡化如下:
#!/bin/bash cd /data/server/tomcat/bin/ ./catalina.sh start tail -f /data/server/tomcat/logs/catalina.out
關閉的原因:
關閉ssh終端窗口時,sshd向下游進程發送SIGHUP
SIGHUP這個信號導致最終關閉進程,具體流程如下:
在非交互模式下,shell對java進程設置了SIGINT
,SIGQUIT
信號設置了忽略,但並沒有對SIGHUP
信號設為忽略。再看一下當時的進程層級:
|-sshd(1622)-+-sshd(11681)---sshd(11699)---bash(11700)---test.sh(13285)---tail(13299)
sshd把SIGHUP
傳遞給bash進程后,bash會把SIGHUP
傳遞給它的子進程,並且對於其子進程test.sh,bash還會對test.sh的進程組里的成員都傳播一遍SIGHUP
。因為java后台進程從父進程catalina.sh(又是從其父進程test.sh)繼承的pgid,所以java進程仍屬於test.sh進程組里的成員,收到SIGHUP
后退出。
解決方案,加入一行 set -m 開啟作業模式:
#!/bin/bash set -m cd /home/admin/tt/tomcat/bin/ ./catalina.sh start tail -f /home/admin/tt/tomcat/logs/catalina.out
此時java后台進程繼承父進程catalina.sh的pgid,而catalina.sh不再使用test.sh的進程組,而是自己的pid作為pgid,catalina.sh進程在執行完退出后,java進程掛到了init下,java與test.sh進程就完全脫離關系了,bash也不會再向它發送信號。
===================
參考:http://ifeve.com/why-kill-2-cannot-stop-tomcat/