近期在玩大數據。有個朋友找過來,說他線上的tomcat會莫名其妙的退出,表示非常苦惱,請我幫看看。每次他發現退出了,都通過騰訊云的WEB控制臺登錄,啟動tomcat。
本著助人為樂(shao kao hao chi)的精神,我連上去開始分析。首先肯定是看tomcat的日志,看看有沒有記錄到相關信息,是什么途徑退出的。
從日志上看,tomcat收到了退出請求,并按照要求關閉容器。那么是否可以認為是有人執行了shutdown.sh呢?并不能。執行了shutdown腳本的關閉日志是這樣的。
與其相關的tomcat源碼截圖如下。截圖左側有行號。
tomcat啟動時,設置await,等待關閉指令進入。org\apache\catalina\startup\Bootstrap.java
catalinaDaemon的定義如下。
org\apache\catalina\startup\Catalina.java
具體實例化時,會將接口Server的實例指向StandardServer。類路徑如下。
org\apache\catalina\Server.java
org\apache\catalina\core\StandardServer.java
而StandServer中的輸出相關日志的源碼如下:
讀取的配置文件為org\apache\catalina\core\LocalStrings.properties
當tomcat收到正經的關閉指令時,會輸出此日志,說明是收到指令關閉容器。
正經的指令關閉容器,相關代碼如下。
那么,現在的證據說明,這個tomcat不是通過SHUTDOWN報文關閉的。而且,從下圖來看,也頗能說明這個SHUTDOWN指令不是這么容易發成功的。
那么現在可能性最大的辦法就是通過KILL指令來操作。執行bash腳本需要登錄機器,那么從wtmp、utmp查找一下這個時間點的登錄記錄呢?
下面是IPIP的結果。
換言之,23日早上tomcat異常退出的時候,有一個來自騰訊云的BGP機房的地址也巧合的斷開了會話。而我這個朋友的機器就放在騰訊云。有點奇怪是嗎?
繼續追查,連續追溯幾天的tomcat日志,比對utmp、wtmp結果,再比對IPIP結果,都是如此。來自騰訊云BGP機房的會話斷開,tomcat同一時間點退出。精確到秒級。連續多天出現很多次,說明tomcat退出和WEB會話退出是具備因果關系的。
經過詢問,朋友確認他是習慣于使用WEB控制臺的方式登錄服務器,啟動了tomcat以后就丟在一邊,開始調試接口了。那么有什么可能會導致這樣的因果關系出現?這就要說到Linux系統的一個歷史悠久的進程間通信的機制——信號量。
具體信號量是什么,請自行查詢相關資料了解學習。針對本次問題,可以簡單的理解為進程間通訊的一種機制。
進程A需要進程B做點事,而進程間的內存區域某種意義上說是互不可見的。這個時候就需要通過信號量來完成。進程A可以按照預先定義的信號量規范向進程B發出信號量,當進程B收到后,根據具體信號量的值決定處理邏輯。具體信號量清單,可以在命令行通過如下命令查詢。命令中均為字母,沒有數字1。
這其中最常見的就是9,SIGKILL。當進程收到此信號量時,會被KILL掉。此信號量由操作系統處理,應用不能處理。在vista之前的windows系統中,是有辦法滲透到內核中的。此時可以攔截類似WM_CLOSE之類的消息,讓某個程序無法關閉。到了win7、win10時代,已經不能使用此類技巧了。
此外,我們熟悉的CTRL + C操作,發出的是SIGINT。有些場景下,我們需要通知程序優雅的退出,此時可以發出SIGQUIT,也就是kill -3。
那么WEB控制臺會話斷開,會發出什么信號量呢?我們來試試就知道了。Java雖然說不能操作系統底層,但是sun.misc包有驚喜哦。代碼如下。
如圖所示,這段代碼會在收到信號量時輸出線程名稱,信號量名稱,并翻譯成具體的數字。隨后,在main函數中,我“注冊”了HUP、INT、ABRT、TERM四種信號量。注冊四種是因為不清楚具體會發什么出來,索性有可能的都搞起來。
編譯,打包。此處有一個問題需要注意,由于信號量屬于操作系統底層機制,每個不同操作系統所支持的信號量是不同的,JVM中通過private static native int findSignal(String paramString)提供支持。native方法涉及具體VM實現,不貼代碼了。不過很容易想到的是,windows和linux當然不同。所以此處就要在上位機編寫,下位機調試了。windows底下運行報錯可不要慌張哦。
接下來的事情就簡單了。把程序上傳服務器,通過WEB控制臺登錄服務器,將執行結果重定向到文本文件中,然后靜待控制臺超時。結果如下。
結果不用再分析了,WEB控制臺會在退出時發出SIGHUP,相當于kill -1。而tomcat在收到SIGHUP會怎么操作呢?小伙伴們可以試試看kill -1 pid,再看看日志,就明白了。
解決方案其實也簡單。SIGHUP是HANG UP的意思,可以用nohup xx.sh &來徹底屏蔽SIGHUP和SIGINT。另外,經過測試發現,通過單擊SecureCRT的tab頁右側的×也可以觸發信號量,而直接logout或者點菜單上的紅叉則并不會觸發。
感興趣的小伙伴可以把這個程序擴展一下,測測看。說不定你的異常退出問題也能迎刃而解呢。
上期介紹了Tomcat如何安裝和啟動,但是依舊有很多小伙伴提出疑問:每次需要的時候都需要進入安裝目錄文件夾點開startup.bat或者命令行里敲startup代碼才能打開,而且運行的時候總會彈出一個黑框。
其實那個黑框一般也沒什么用,只能看看運行狀態啥的,放著總是有點礙眼,關又不能關,強迫癥人群即使最小化了也會覺得不舒服。所以能不能讓它運行的時候沒有那個黑框界面,最好開機就自啟動,不用每次都點開?畢竟這個服務器占用的資源也不多。
Tomcat運行界面
我的回答是當然可以啦!只需要將Tomcat安裝成服務,然后設置成開機自啟動就可以了。接下來我就手把手地帶大家展示一下如何操作。
bin目錄下新建文本文檔
重命名文檔名字
右鍵編輯剛創建的cmd.bat文件
輸入cmd并保存
右鍵,以管理員身份運行cmd.bat
【注:輸入CD后敲個空格,可右鍵將剛才復制的路徑粘貼到命令行窗口中】
D:
CD D:\Program Files\apache-tomcat-8.0.41\bin\
service.bat install
此時該服務已經安裝到了電腦中,如果想啟動的話可以在命令行窗口中輸入如下命令
net start Tomcat8
如果想設置成開機自啟的話,可以按快捷鍵Win+R打開運行窗口,輸入services.msc,打開服務窗口,找到Apache Tomcat8.0 Tomcat8,右鍵點擊屬性,將啟動類型設置為自動即可。每次開機的時候就會自動啟動,很是方便,占用不了多少系統資源,可以放心在后臺運行。
進入服務中設置為開機自啟
那么問題來了,如果我什么時候不想用了,如何關閉和卸載服務呢?很簡單,只需按快捷鍵Win+R,輸入cmd,打開命令行窗口輸入如下指令即可:
net stop Tomcat8
service.bat remove
這就是我給大家分享的全部內容,如果大家覺得有幫助,歡迎關注評論或轉發,您的支持就是我更新的動力!