文章目錄
線程 dump 分析是找出服務器響應緩慢、服務器掛起、粘滯線程導致服務器崩潰等問題原因的最重要的一個手段。本文我們將了解到 Weblogic 線程模型以及這些線程所執行的功能和任務的一些非常基本但卻很重要特性。本文將對我們在分析線程 dump 或者服務器掛起等場景所使用的一些通用術語進行討論。
服務器掛起是什么情況,它有哪有症狀?
- 如果一台服務器的響應速度跟預估的響應時間相比非常慢的話,那么它可能處於整個服務器掛起的情況了。
- 如果一台服務器甚至對客戶端的請求都沒有響應,那么這就是一個服務器完全掛起的場景了。有時服務器的完全阻塞也會引起服務器崩潰。
Weblogic 線程的角色和職責?
Weblogic 線程大致可以分為兩大類。
- Weblogic Execute 線程:這種線程負責處理客戶/用戶請求。它決定了一台服務器可以並行執行多少個任務。在開發模式下 WLS 服務器會默認持有 15 個 Execute 線程而如果是生產模式 WLS 服務器將會默認持有 25 個線程。但只是提高 Execute 線程的數量並不意味着性能的提升…相反在某些情況下這反而會降低性能。
- Weblogic Socket Reader 線程:這類線程對進入的客戶端請求進行監聽。這也就意味着這些線程基本上負責的是處理網絡流量部分的工作。它們屬於 Execute 線程的一部分,默認情況下會占用 33% 的 Execute 線程。也就是說在默認情況下會有 33% 的 Execute 線程是為 Socket Reader 線程,可以根據實際需求對其進行調整。
舉例說明:如果開發模式下的 WLS 服務器擁有 15 個 Execute 線程,那么會有 5 個線程是 Socket Reader 線程而其他 10 個線程負責實際客戶請求的處理。
什么是 Execute 隊列?
Execute 隊列是一組負責指定的 Servlet / RMI 對象 / EJB / JSP 請求的 Execute 線程。在 WLS8.1 之前我們可以看到這些 Execute 隊列信息是屬於 “config.xml” 的一部分。但從 WLS9.x 開始,隨着 Weblogic 線程模型由於引入了 WorkManager 的改變,我們在 WLS9.x 及以后版本的 WLS 中默認就看不到 Execute 隊列的細節了。但是如果我們想在 WLS9.x 或更高版本的 Weblogic 中使用 WLS8.1 樣式的線程模型的話我們可以使用這一 JAVA_OPTION:-Dweblogic.Use81StyleExecuteQueues=true
服務器掛起可能會有哪些原因?
服務器響應緩慢或者掛起背后可能會有很多原因…
原因一。如果可用的堆內存很小的話線程將無法在 Java 堆內存中創建所需的對象。
原因二。線程數量不足。通常發生在服務器負載 (用戶請求數量) 突然增加而 MaxThreadCount 沒有設置為一個合理的值的情況下,這種時候服務器將無法處理這些請求。
原因三。如果垃圾收集工作在占用很多時間,這種情況下垃圾數據的清理過程將會 (比正常情況下) 花費更長時間以至於所有線程被用於進行垃圾收集的工作而不是處理客戶端請求。或者就是線程們在等待垃圾收集清理出來新的空間以創建新的對象。
原因四。有時候 Java (編譯器) 的代碼優化也會引起一個臨時的掛起,這是因為代碼優化是一個有點重的過程但卻有助於獲得更好的性能。
原因五。一些遠程 JDBC 查找有時也會引起服務器掛起。
原因六。不恰當的 JSP 編譯設置。(建議在將 JSP 部署到生產環境之前對其進行預編譯並且正確設置 PageCheckSeconds 以便 JSP 編譯不會頻繁發生)
原因七。應用代碼死鎖或 JDBC 驅動死鎖或第三方 API Bug:當線程在無限循環中等待獲得對對象的鎖定時…比如以下場景。
- 線程 Thread_A 拿到了對象 Obj_A 的鎖。
- 線程 Thread_B 拿到了對象 Obj_B 的鎖。
- 現在線程 Thread_A 在處理完針對 Obj_A 的一些邏輯之后開始請求對象 Obj_B 的鎖 (對象 Obj_B 還在被線程 Thread_B 鎖定中)。
- 與此類似,線程 Thread_B 在處理完針對 Obj_B 的一些邏輯之后開始請求對象 Obj_A 的鎖 (對象 Obj_A 還在被線程 Thread_A 鎖定中)。
在這種情況下,兩個線程都在等待對方釋放所鎖定的對象…但實際情況下它們誰也無法釋放自己已經鎖定的那個對象。
原因八。分配給進程的系統文件描述符的數量非常小 (資源不足),在這種情況下我們也可能會面臨服務器響應慢或者掛起的情形。
如果出現服務器掛起或響應緩慢的情形,服務端的日志是什么樣子的?
Weblogic 將一個線程標記為 STUCK 線程的默認時間間隔是 600 秒 (也就是 10 分鍾)。當出現 STUCK 線程時服務端日志會對此進行詳細記錄,所以你可以在服務端日志中找到如下日志:
<Warning> <WebLogicServer> <BEA-000337> <ExecuteThread: '7' for queue: 'weblogic.kernel.Default' has been busy for "630" seconds working on the request "weblogic.ejb20.internal.JMSMessagePoller@d64412", which is more than the configured time (StuckThreadMaxTime) of "600" seconds.>
服務器端出現上述這種日志是不是就意味着 Weblogic 已經掛起?
上述日志信息只是指示出有些線程在處理一些請求時占用了過多的時間,這當然會導致 Weblogic 服務器響應緩慢,同時這有可能會導致服務器掛起。但這並不 100% 意味着 Weblogic 無法從這些線程中恢復正常。
Weblogic 有能力將一個 STUCK 線程標記為 UNSTUCK。Weblogic 會根據 “Stuck Thread Max Time” 和 “Stuck Thread Timer Interval” 的設置對 STUCK 線程進行定期檢查,請參考官方文檔 http://e-docs.bea.com/wls/docs103/ConsoleHelp/taskhelp/tuning/TuningExecuteThreads.html。
Weblogic 只是對線程標記為 STUCK 進行報告,隨着線程的處理結束 (可能看起來是卡住了,實際上是在運行一個很長的事務),Weblogic 還會將其標記為 UNSTUCK。很多時候應用需求確實需要線程花費很多時間來處理客戶端請求 (多余 600 秒),在這種情況下屋面可以改變 “StuckThreadMaxTime” 的時間間隔。比方說我們的應用有一些需要長時間運行的 JDBC 查詢可能會占用 900 多秒,這時候我們就可以增大 StuckThreadMaxTime 了。
收集調試數據需要哪些應急步驟?
調試一。使用 “weblogic.Admin PING” 工具 ping Weblogic 服務器五到六次來看看我們需要多久才能得到響應返回?
java weblogic.Admin -url t3://StuckThreadHostName:9001 -username weblogic -password weblogic PING
調試二。立刻檢查詳細的 GC 日志 (前提是你已經通過以下 JAVA_OPTIONS 啟用了 GC 日志)。
set JAVA_OPTIONS=%JAVA_OPTIONS% -Xloggc:/opt/logs/gc.log -XX:+PrintGCDetails -Xmx1024m -Xms1024m
調試三。在九到十秒之間收集至少四到五次線程 DUMP 來查看線程的活躍度。遵循各種線程 DUMP 的收集方法:http://middlewaremagic.com/weblogic/?p=823。
調試四。檢查服務器負載 (客戶端請求數) 是不是異常高?
調試五。檢查 JMS 子系統連接或數據庫連接是否在某個地方丟失了…你可能會在服務器日志中發現一些奇怪的條目,比如說 DataSource is Disables/ Network Adapter could not Establish Connection to the Database/ JMS Messaging System “PeerGoneException”…Tuxedo/Jolt Connectivity Errors…等等。
轉自https://defonds.blog.csdn.net/article/details/103865374