在網路品質不佳或高負載環境下,WebLogic Server 常在日誌中出現兩種與 HttpCompleteMessageTimeout 相關的異常:BEA-101083(請求讀取逾時)與 BEA-101326(回應傳送逾時)。本文從原始碼層面剖析兩者成因、觸發機制、參數調整差異,並提供實務調優建議。
| 異常代碼 | 發生階段 | 錯誤訊息關鍵字 | 預設逾時 |
|---|---|---|---|
| BEA-101083 | Client → Server 請求傳輸 | A complete message could not be read on socket | 60 秒 |
| BEA-101326 | Server → Client 回應傳輸 | The server could not send the HTTP message during the configured timeout value | 60 秒 |
CompleteMessageTimeout(適用 T3、IIOP 等所有協定)。CompleteMessageTimeoutTrigger.CLEANUP_TRIGGER_TIMEPERIOD_LOW = 2 秒。關鍵觀念:此逾時針對「單一網路封包(Chunk)傳輸時間」,而非整個 HTTP Request/Response 的總時間。
WebLogic 將回應資料切分為多個 Chunk(預設 4080 bytes,可用 -Dweblogic.ChunkSize 調整)。每次寫入一個 Chunk 時,會將 OutputStream 註冊到 CompleteMessageTimeoutTrigger:
static void writeChunks(Chunk header, Chunk c, OutputStream os, int size, boolean chunkXfer) throws IOException {
try {
trigger.register(os); // 註冊逾時監控
if (chunkXfer) writeChunkTransfer(...);
else writeChunkNoTransfer(...);
} finally {
trigger.unregister(os); // 寫完移除監控
}
}
HttpCompleteMessageTimeout 內未寫完 → 觸發 BEA-101326,關閉 Socket,剩餘資料中斷。unregister,Trigger 不再追蹤該 Stream。Server 端由 SocketMuxer.TimeoutTrigger 定期檢查:
final int checkTimeout(long idleTimeout, long msgTimeout) {
if (messagePending()) {
if (msgTimeout <= 0) return OKAY;
long interval = getMessageIntervalMillis(msgTimeout);
if (interval <= msgTimeout) return OKAY;
return MSG_TIMEOUT; // 觸發 BEA-101083
}
// idle timeout 檢查...
}
messagePending():正在讀取 Request 封包。getMessageIntervalMillis():計算從開始讀取到現在經過的毫秒數。SocketInfo.lastIoInitiatedTimeMillis 記錄最後一次 Socket I/O 時間,用於控制 KeepAlive 連線空閒逾時(預設 30 秒)。
| 異常 | Trigger 類別 | 初始化方式 | 參數讀取時機 | 動態生效 |
|---|---|---|---|---|
| BEA-101083 | SocketMuxer.TimeoutTrigger | Instance per Muxer | 每次 trigger 執行時重新讀取 | 是 |
| BEA-101326 | ChunkUtils.CompleteMessageTimeoutTrigger | static 靜態變數,Class Loading 時單次初始化 | 靜態初始化區塊 static { trigger = new ...(); } | 否(需重啟) |
因為 ChunkUtils 的 Trigger 是 static,JVM 載入類別時只讀取一次設定;修改 Console 設定後必須重啟 Server 才能讓新值生效。
IdleTimeout(KeepAlive)與 CompleteMessageTimeout 兩者關係,避免設定衝突。理解 HttpCompleteMessageTimeout 作用於「單一 Chunk」而非整個 Request/Response,並掌握兩種 Trigger 的初始化差異,才能精準調優並避免「以為設定生效實際未生效」的坑。網路層面的根治永遠優於單純拉長逾時參數。