TOP

(轉)tomcat進程意外退出的問題分析(一)
2017-10-13 10:21:36 】 瀏覽:10149
Tags:

節前某個部門的測試環境反饋tomcat會意外退出优乐棋牌app下载,我們到實際環境排查后發現不是jvm crash,日志里有進程銷毀的記錄,從pause到destory的整個過程:

org.apache.coyote.AbstractProtocol pause
Pausing ProtocolHandler
org.apache.catalina.core.StandardService stopInternal
Stopping service Catalina
org.apache.coyote.AbstractProtocol stop
Stopping ProtocolHandler
org.apache.coyote.AbstractProtocol destroy
Destroying ProtocolHandler

從上面日志來可以判斷:

1) tomcat不是通過腳本正常關閉(viaport: 即通過8005端口發送shutdown指令)

因為正常關閉(viaport)的話會在 pause 之前有這樣的一句warn日志:

    org.apache.catalina.core.StandardServer await
    A valid shutdown command was received via the shutdown port. Stopping the Server instance.
    然后才是 pause -> stop -> destroy 
2) tomcat的shutdownhook被觸發,執行了銷毀邏輯

而這又有兩種情況,一是應用代碼里有地方用System.exit來退出jvm优乐棋牌app下载,二是系統發的信號(kill -9除外,SIGKILL信號JVM不會有機會執行shutdownhook)

先通過排查代碼,應用方和中間件團隊都排查了System.exit在這個應用中使用的可能。那就只剩下Signal的情況了;經過一番排查后,發現每次tomcat意外退出的時間與ssh會話結束的時間正好吻合。

有了這個線索之后,銀時同學立刻看了一下對方測試環境的腳本,簡化后如下:

$ cat test.sh
#!/bin/bash
cd /data/server/tomcat/bin/
./catalina.sh start
tail -f /data/server/tomcat/logs/catalina.out

tomcat啟動為后,當前shell進程并沒有退出,而是掛住在tail進程,往終端輸出日志內容。這種情況下,如果用戶直接關閉ssh終端的窗口(用鼠標或快捷鍵)优乐棋牌app下载,則java進程也會退出。而如果先ctrl-c終止test.sh進程,然后再關閉ssh終端的話,則java進程不會退出。

這是一個有趣的現象,catalina.sh start方式啟動的tomcat會把java進程掛到init(進程id為1)的父進程下,已經與當前test.sh進程脫離了父子關系,也與ssh進程沒有關系,為什么關閉ssh終端窗口會導致java進程退出?

我們的推測是ssh窗口在關閉時,對當前交互的shell以及正在運行的test.sh等子進程發送某個退出的Signal,找了一臺裝有systemtap的機器來驗證,所用的stap腳本是從澗泉同學那里copy的:

function time_str: string () {
    return ctime(gettimeofday_s() + 8 * 60 * 60);
}
probe begin {
    printdln(" ", time_str(), "BEGIN");
}
probe end {
    printdln(" ", time_str(), "END");
}
probe signal.send {
    if (sig_name == "SIGHUP" || sig_name == "SIGQUIT" || 
        sig_name=="SIGINT" || sig_name=="SIGKILL" || sig_name=="SIGABRT") {
        printd(" ", time_str(), sig_name, "[", uid(), pid(), cmdline_str(), 
                "] -> [", task_uid(task), sig_pid, pid_name, "], ");
        task = pid2task(pid());
        while (task_pid(task) > 0) {
            printd(" ", "[", task_uid(task), task_pid(task), task_execname(task), "]");
            task = task_parent(task);
        }
        println("");
    }
}

模擬時的進程層級(pstree)大致如下,tomcat啟動后java進程已經脫離test.sh,掛在init下:

|-sshd(1622)-+-sshd(11681)---sshd(11699)---bash(11700)---test.sh(13285)---tail(13299)

經過內核組伯俞的協助,我們發現

a) 用 ctrl-c 終止當前test.sh進程時,系統events進程向 java 和 tail 兩個進程發送了SIGINT 信號
SIGINT [ 0 11  ] -> [ 0 20629 tail ] 
SIGINT [ 0 11  ] -> [ 0 20628 java ] 
SIGINT [ 0 11  ] -> [ 0 20615 test.sh ] 
注pid 11是events進程
b) 關閉ssh終端窗口時,sshd向下游進程發送SIGHUP, 為何java進程也會收到?
SIGHUP [ 0 11681 sshd: hongjiang.wanghj [priv] ] -> [ 57316 11700 bash ] 
SIGHUP [ 57316 11700 -bash ] -> [ 57316 11700 bash ]
SIGHUP [ 57316 11700 ] -> [ 0 13299 tail ] 
SIGHUP [ 57316 11700 ] -> [ 0 13298 java ] 
SIGHUP [ 57316 11700 ] -> [ 0 13285 test.sh ] 

不過伯俞很忙沒有繼續協助分析這個問題(他給出了一些猜測,但后來證明并不是那樣)。

確定了是由signal引起的之后,我的疑惑變成了:

1) 為什么SIGINT (kill -2) 不會讓tomcat進程退出?
2) 為什么SIGHUP (kill -1) 會讓tomcat進程退出?

我第一反應可能是jvm在某些參數下(或因為某些jni)對os的信號處理會不同,看了一下應用的jvm參數,沒有看出問題,也排除了tomcat使用apr/tcnative的情況。

我們看一下默認情況下,jvm進程對SIGINTSIGHUP是怎么處理的,用scala的repl模擬一下:

scala> Runtime.getRuntime  
		

請關注公眾號獲取更多資料



首頁 上一頁 1 2 下一頁 尾頁 1/2/2
】【打印繁體】【】【】 【】【】【】 【關閉】 【返回頂部
上一篇分布式搜索引擎Elasticsearch的查.. 下一篇linux(六)__進程與任務控制