一次因信號(hào)量引發(fā)的tomcat異常退出解決
近期在玩大數(shù)據(jù)。有個(gè)朋友找過來,說他線上的tomcat會(huì)莫名其妙的退出,表示非常苦惱,請我?guī)涂纯?。每次他發(fā)現(xiàn)退出了,都通過騰訊云的WEB控制臺(tái)登錄,啟動(dòng)tomcat。
本著助人為樂(shao kao hao chi)的精神,我連上去開始分析。首先肯定是看tomcat的日志,看看有沒有記錄到相關(guān)信息,是什么途徑退出的。
從日志上看,tomcat收到了退出請求,并按照要求關(guān)閉容器。那么是否可以認(rèn)為是有人執(zhí)行了shutdown.sh呢?并不能。執(zhí)行了shutdown腳本的關(guān)閉日志是這樣的。
與其相關(guān)的tomcat源碼截圖如下。截圖左側(cè)有行號(hào)。
tomcat啟動(dòng)時(shí),設(shè)置await,等待關(guān)閉指令進(jìn)入。org\apache\catalina\startup\Bootstrap.java
catalinaDaemon的定義如下。
org\apache\catalina\startup\Catalina.java
具體實(shí)例化時(shí),會(huì)將接口Server的實(shí)例指向StandardServer。類路徑如下。
org\apache\catalina\Server.java
org\apache\catalina\core\StandardServer.java
而StandServer中的輸出相關(guān)日志的源碼如下:
讀取的配置文件為org\apache\catalina\core\LocalStrings.properties
當(dāng)tomcat收到正經(jīng)的關(guān)閉指令時(shí),會(huì)輸出此日志,說明是收到指令關(guān)閉容器。
正經(jīng)的指令關(guān)閉容器,相關(guān)代碼如下。
那么,現(xiàn)在的證據(jù)說明,這個(gè)tomcat不是通過SHUTDOWN報(bào)文關(guān)閉的。而且,從下圖來看,也頗能說明這個(gè)SHUTDOWN指令不是這么容易發(fā)成功的。
那么現(xiàn)在可能性最大的辦法就是通過KILL指令來操作。執(zhí)行bash腳本需要登錄機(jī)器,那么從wtmp、utmp查找一下這個(gè)時(shí)間點(diǎn)的登錄記錄呢?
下面是IPIP的結(jié)果。
換言之,23日早上tomcat異常退出的時(shí)候,有一個(gè)來自騰訊云的BGP機(jī)房的地址也巧合的斷開了會(huì)話。而我這個(gè)朋友的機(jī)器就放在騰訊云。有點(diǎn)奇怪是嗎?
繼續(xù)追查,連續(xù)追溯幾天的tomcat日志,比對utmp、wtmp結(jié)果,再比對IPIP結(jié)果,都是如此。來自騰訊云BGP機(jī)房的會(huì)話斷開,tomcat同一時(shí)間點(diǎn)退出。精確到秒級(jí)。連續(xù)多天出現(xiàn)很多次,說明tomcat退出和WEB會(huì)話退出是具備因果關(guān)系的。
經(jīng)過詢問,朋友確認(rèn)他是習(xí)慣于使用WEB控制臺(tái)的方式登錄服務(wù)器,啟動(dòng)了tomcat以后就丟在一邊,開始調(diào)試接口了。那么有什么可能會(huì)導(dǎo)致這樣的因果關(guān)系出現(xiàn)?這就要說到Linux系統(tǒng)的一個(gè)歷史悠久的進(jìn)程間通信的機(jī)制——信號(hào)量。
具體信號(hào)量是什么,請自行查詢相關(guān)資料了解學(xué)習(xí)。針對本次問題,可以簡單的理解為進(jìn)程間通訊的一種機(jī)制。
進(jìn)程A需要進(jìn)程B做點(diǎn)事,而進(jìn)程間的內(nèi)存區(qū)域某種意義上說是互不可見的。這個(gè)時(shí)候就需要通過信號(hào)量來完成。進(jìn)程A可以按照預(yù)先定義的信號(hào)量規(guī)范向進(jìn)程B發(fā)出信號(hào)量,當(dāng)進(jìn)程B收到后,根據(jù)具體信號(hào)量的值決定處理邏輯。具體信號(hào)量清單,可以在命令行通過如下命令查詢。命令中均為字母,沒有數(shù)字1。
這其中最常見的就是9,SIGKILL。當(dāng)進(jìn)程收到此信號(hào)量時(shí),會(huì)被KILL掉。此信號(hào)量由操作系統(tǒng)處理,應(yīng)用不能處理。在vista之前的windows系統(tǒng)中,是有辦法滲透到內(nèi)核中的。此時(shí)可以攔截類似WM_CLOSE之類的消息,讓某個(gè)程序無法關(guān)閉。到了win7、win10時(shí)代,已經(jīng)不能使用此類技巧了。
此外,我們熟悉的CTRL + C操作,發(fā)出的是SIGINT。有些場景下,我們需要通知程序優(yōu)雅的退出,此時(shí)可以發(fā)出SIGQUIT,也就是kill -3。
那么WEB控制臺(tái)會(huì)話斷開,會(huì)發(fā)出什么信號(hào)量呢?我們來試試就知道了。Java雖然說不能操作系統(tǒng)底層,但是sun.misc包有驚喜哦。代碼如下。
如圖所示,這段代碼會(huì)在收到信號(hào)量時(shí)輸出線程名稱,信號(hào)量名稱,并翻譯成具體的數(shù)字。隨后,在main函數(shù)中,我“注冊”了HUP、INT、ABRT、TERM四種信號(hào)量。注冊四種是因?yàn)椴磺宄唧w會(huì)發(fā)什么出來,索性有可能的都搞起來。
編譯,打包。此處有一個(gè)問題需要注意,由于信號(hào)量屬于操作系統(tǒng)底層機(jī)制,每個(gè)不同操作系統(tǒng)所支持的信號(hào)量是不同的,JVM中通過private static native int findSignal(String paramString)提供支持。native方法涉及具體VM實(shí)現(xiàn),不貼代碼了。不過很容易想到的是,windows和linux當(dāng)然不同。所以此處就要在上位機(jī)編寫,下位機(jī)調(diào)試了。windows底下運(yùn)行報(bào)錯(cuò)可不要慌張哦。
接下來的事情就簡單了。把程序上傳服務(wù)器,通過WEB控制臺(tái)登錄服務(wù)器,將執(zhí)行結(jié)果重定向到文本文件中,然后靜待控制臺(tái)超時(shí)。結(jié)果如下。
結(jié)果不用再分析了,WEB控制臺(tái)會(huì)在退出時(shí)發(fā)出SIGHUP,相當(dāng)于kill -1。而tomcat在收到SIGHUP會(huì)怎么操作呢?小伙伴們可以試試看kill -1 pid,再看看日志,就明白了。
解決方案其實(shí)也簡單。SIGHUP是HANG UP的意思,可以用nohup xx.sh &來徹底屏蔽SIGHUP和SIGINT。另外,經(jīng)過測試發(fā)現(xiàn),通過單擊SecureCRT的tab頁右側(cè)的×也可以觸發(fā)信號(hào)量,而直接logout或者點(diǎn)菜單上的紅叉則并不會(huì)觸發(fā)。
感興趣的小伙伴可以把這個(gè)程序擴(kuò)展一下,測測看。說不定你的異常退出問題也能迎刃而解呢。
此問題的解決離不開上海中通的劉建剛同學(xué),特此致謝。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。
相關(guān)文章
Linux系統(tǒng)centos7.X安裝tomcat8的圖文教程
這篇文章主要介紹了Linux系統(tǒng)centos7.X安裝tomcat8的圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Tomcat怎么實(shí)現(xiàn)異步Servlet
這篇文章主要介紹了Tomcat怎么實(shí)現(xiàn)異步Servlet,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧。2017-01-01使用Tomcat無法訪問http:localhost:8080的解決方法
本文主要介紹了使用Tomcat無法訪問http:localhost:8080的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05Tomcat監(jiān)測腳本的實(shí)現(xiàn)示例
這篇文章主要給大家介紹了Tomcat監(jiān)測腳本的實(shí)現(xiàn)方法,文中給出了詳細(xì)的示例代碼和介紹,對大家具有一定的參考價(jià)值,有需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)把。2017-01-01深入了解tomcat中servlet的創(chuàng)建方式實(shí)現(xiàn)
這篇文章主要介紹了深入了解tomcat中servlet的創(chuàng)建方式實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10SpringBoot?升級(jí)內(nèi)嵌Tomcat的操作示例
這篇文章主要介紹了SpringBoot升級(jí)內(nèi)嵌Tomcat,這里采用的是屏蔽舊的依賴,然后手動(dòng)寫dependency的方式,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08Eclipse創(chuàng)建tomcat實(shí)現(xiàn)過程原理詳解
這篇文章主要介紹了Eclipse創(chuàng)建tomcat實(shí)現(xiàn)過程原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09