Apache+Tomcat 有通信問題。不清楚的錯誤資訊。關閉託管在 Tomcat 下的網站
設置:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache 正在使用 AJP 轉發請求。
問題:
經過一段時間(完全沒有常數,可能在一兩個小時之間,或者一天或多天)之後,Tomcat 會宕機。它要麼停止響應,要麼提出通用的“服務暫時不可用”。
診斷:
有兩台伺服器具有相同的設置。一個是流量較高的網站(每秒幾個請求),另一個是低流量的網站(每隔幾分鐘就有幾個請求)。這兩個網站是完全不同的程式碼庫,但它們表現出相似的問題。
在第一台伺服器上,當問題發生時,所有執行緒都會慢慢開始佔用,直到達到限制(MaxThreads 200)。此時伺服器不再響應(並且在很長一段時間後出現服務不可用頁面)。
在第二台伺服器上,當問題發生時,請求需要很長時間,當它們完成後,您所看到的只是服務不可用頁面。
除了提到 MaxThreads 問題之外,Tomcat 日誌沒有指出任何可能導致此問題的具體問題。
但是,在 Apache 日誌中,我們看到隨機消息指代 AJP。這是我們看到的隨機消息範例(沒有特定順序):
[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header [error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header [error] proxy: AJP: disabled connection for (localhost) [error] ajp_read_header: ajp_ilink_receive failed [error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost) [error] ap_proxy_connect_backend disabling worker for (localhost)
我們在更高流量的伺服器上註意到的另一件奇怪的事情是,在問題開始發生之前,數據庫查詢花費的時間比以前長得多(2000-5000 毫秒,而通常為 5-50 毫秒)。在 MaxThreads 消息出現之前,這只持續 2-4 秒。我假設這是伺服器突然處理太多數據/流量/執行緒的結果。
背景資訊:
這兩台伺服器已經執行了很長一段時間沒有問題。在此期間,這些系統實際上是使用兩個 NIC 設置的。他們將內部和外部流量分開。網路升級後,我們將這些伺服器移至單個 NIC(出於安全/簡單的原因,我們建議這樣做)。更改後,伺服器開始出現這些問題。
解決方案:
顯而易見的解決方案是回到兩個 NIC 的設置。這樣做的問題是它會導致網路設置的一些複雜性,並且似乎忽略了這個問題。我們更願意嘗試讓它在單個 NIC 設置上執行。
Google搜尋各種錯誤消息並沒有提供任何有用的資訊(舊的解決方案或與我們的問題無關)。
我們已經嘗試調整各種超時,但這只會讓伺服器在當機前執行稍長一些。
我們不確定在哪裡可以進一步診斷問題。我們仍然在抓住可能出現的問題的稻草:
AJP 和 Tomcat 的設置不正確或過時(即已知錯誤?)
網路設置(兩個 NIC 與一個 NIC)導致混亂或吞吐量問題。
網站本身(沒有通用程式碼,沒有使用平台,只有帶有 servlet 和 JSP 的基本 Java 程式碼)
更新 1:
根據 David Pashley 的有用建議,我在問題期間進行了堆棧跟踪/執行緒轉儲。我發現所有 200 個執行緒都處於以下狀態之一:
"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0] at oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988) - waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl) [further stack trace removed for brevity] "TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0] at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268) - waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl) [further stack trace removed for brevity]
奇怪的是,所有 200 個執行緒中只有一個執行緒處於這種狀態:
"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30] at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at oracle.net.ns.Packet.receive(Unknown Source) at oracle.net.ns.DataPacket.receive(Unknown Source) at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source) at oracle.net.ns.NetInputStream.read(Unknown Source) at oracle.net.ns.NetInputStream.read(Unknown Source) at oracle.net.ns.NetInputStream.read(Unknown Source) [further stack trace removed for brevity]
可能是該執行緒中的 Oracle 驅動程序正在強制所有其他執行緒等待它完成。由於某種原因,它必須停留在這種讀取狀態(伺服器永遠不會自行恢復,它需要重新啟動)。
這表明它必須與伺服器和數據庫之間的網路或數據庫本身有關。我們正在繼續進行診斷工作,但任何提示都會有所幫助。
事實證明,這個版本的 Oracle 驅動程序(classes12 - 相當舊)中存在各種導致死鎖的錯誤(如上面引用的 TP-Processor2 狀態所示)。直到我們切換到新環境,它才變得活躍。升級到最新版本 (ojdbc14) 已解決主伺服器上的問題。
從描述中,我認為問題可能是由於數據庫查詢花費的時間太長。如果查詢花費的時間更長,請求將花費更長的時間,因此您將同時執行更多的查詢。如您所見,您的tomcat 執行緒已用完。當您解決數據庫問題時,您應該沒問題。
- 使用 jstack 或使用 kill -3 $process_id 獲取堆棧跟踪。看看你的執行緒在它死時在做什麼。如果他們都在等待數據庫,這是我理論的一個很好的指針。他們可能都在等待某個鎖。
- 安裝 LambdaProbe。找出你的tomcat在做什麼是非常寶貴的。
- 升級你的tomcat。5.5.8 太老了。我想他們現在在 5.5.27。