某 Windows Server 2003 + IIS 6.0 生產環境,運行約 70 個網站,出現「ASP 頁面無法存取、CGI/PHP/HTM/JSP 正常」的間歇性假死現象,每日需重啟 IIS 恢復。經排查鎖定為預設應用程式集區回收機制與高併發請求衝突。本文詳細分析根因、提供單站/多站優化配置方案、驗證結果與進階排查建議。
現象描述與初步判斷
- 症狀: 僅 ASP (經典 ASP) 請求掛起/回應極慢/500 錯誤;ASP.NET (ASPX)、PHP、CGI、靜態檔案 (HTM/JS/CSS/圖片) 正常。
- 頻率: 不定時,高峰期頻繁,低峰期罕見。
- 臨時修復: IIS 管理員 → 重啟 IIS (
iisreset) 即時恢復。
- 關鍵線索: 僅 ASP 受影響 → 指向 ASP 執行環境 (ASP.dll 載入於 IIS 6.0 工作進程) 與應用程式集區行為相關。
根因深度剖析:應用程式集區回收與請求佇列阻塞
IIS 6.0 應用程式集區回收機制
- 預設單一應用程式集區 (
DefaultAppPool) 服務所有網站。
- 回收觸發條件:時間間隔 (預設 1740 分鐘 = 29 小時)、請求數上限、記憶體上限、排程時間、設定變更。
- 回收過程:啟動新工作進程 (w3wp.exe) → 新進程啟動完成開始接收請求 → 舊進程停止接收新請求 → 等待現有請求完成 (最長
ShutdownTimeLimit 預設 90 秒) → 強制終止殘留請求 → 釋放資源。
衝突場景重構
- 高併發時段,大量 ASP 請求湧入單一集區。
- 集區達到請求佇列上限 (Queue Length 預設 1000) 或記憶體壓力觸發回收。
- 回收啟動,新舊 w3wp.exe 共存過渡期。
- ASP 執行引擎 (
asp.dll) 在舊進程中處理長時間請求 (資料庫查詢、COM 元件呼叫、檔案 I/O) 導致請求無法在 ShutdownTimeLimit 內完成。
- 舊進程被強制終止,正在執行的 ASP 請求瞬間中斷,客戶端收到連線重設/逾時。
- 新進程 ASP 引擎初始化尚未完成 (載入腳本引擎、編譯模板、建立資料庫連線池),新請求排隊/失敗。
- 循環惡化:請求積壓 → 更多回收觸發 → 服務持續不可用。
為何僅 ASP 受影響? ASP.NET (ASPX) 由 aspnet_isapi.dll 處理,擁有獨立編譯/快取機制,對進程回收彈性較佳;PHP/CGI/JSP 運行於獨立進程 (FastCGI/ISAPI/servlet 容器),不受 IIS 工作進程回收直接影響。
解決方案:應用程式集區隔離與回收參數優化
方案 A:單一網站環境 (簡單有效)
- IIS 管理員 → 應用程式集區 →
DefaultAppPool 右鍵內容。
- 回收索引標籤:
- 「定期回收時間 (分鐘)」: 1740 → 300~600 (5~10 小時),縮短回收週期,避免長時間累積記憶體洩漏/句柄洩漏。
- 「在下列時間回收」: 勾選 05:00 (業務低谷期),確保每日固定時間溫和重啟。
- 取消勾選「請求數上限」、「記憶體上限」 (或設為極大值),避免業務高峰被動觸發回收。
- 效能索引標籤: 「關閉閒置工作進程」時間可適當延長 (預設 20 分鐘),減少頻繁啟停開銷。
方案 B:多網站環境 (生產級推薦) —— 核心策略:業務隔離 + 記憶體預算
- 建立多個應用程式集區: 依流量/重要性分組。筆者案例:70 個網站 → 建立 6 個集區,每池 ~10-12 個網站。
- 大流量/關鍵網站獨享集區: 流量佔比 > 20% 或 業務關鍵 (電商、核心系統) → 單獨集區,獨享記憶體/CPU 配額。
- 配置各集區回收參數:
- 回收時間:300 分鐘 (5 小時)。
- 排程回收:05:00 (錯峰,避免同時回收衝擊)。
- 記憶體上限:依伺服器總 RAM 分配。案例:單池 ~120MB 工作集,6 池 ~720MB,留足系統/其他服務記憶體。
- 指派網站至對應集區:
- IIS 管理員 → 右鍵目標網站 → 內容 → 主目錄索引標籤。
- 「應用程式集區」下拉選單選擇對應集區名稱 → 確定。

方案 C:進階優化 (配合方案 B)
- 啟用「快速失敗保護」: 集區 → 內容 → 健康偵測 → 勾選「啟用快速失敗保護」、失敗次數 5、時間間隔 5 分鐘、離線時間 5 分鐘。防止惡性循環回收拖垮整台伺服器。
- 調整佇列長度: 集區 → 內容 → 效能 → 「要求佇列限制」: 1000 → 2000~5000 (視記憶體而定),緩衝突發流量。
- 預載應用程式池 (IIS 7.0+):
startMode="AlwaysRunning" + preloadEnabled="true",消除冷啟動延遲。IIS 6.0 可用腳本定時喚醒。
- ASP 專項調優:
MetaBase.xml → ASPProcessorThreadMax (預設 25) 依 CPU 核心數調大;ASPRequestQueueMax 增大;ASPScriptTimeout 延長 (預設 90 秒) 避免長查詢中斷。
驗證結果與效益量化
| 指標 | 優化前 | 優化後 | 改善幅度 |
| ASP 假死頻率 | 幾乎每日 1 次 | 連續 30 天 0 次 | 100% 消除 |
| 平均回應時間 (ASP) | 高峰期 > 10 秒 (含失敗) | 穩定 < 500ms | > 95% 降低 |
| IIS 重啟次數 | 每日 1~2 次 | 0 次 (僅排程維護) | 100% 減少 |
| 記憶體使用穩定性 | 波動大、頻繁回收 | 平緩鋸齒波、可預測 | 質的飛躍 |
記憶體成本:單集區 ~120MB,6 集區 ~720MB,現代伺服器 (8GB~64GB RAM) 完全可接受。以記憶體換取隔離與穩定,ROI 極高。
網站程式碼層面的潛在根因 (若上述方案無效)
站長註解:此類情況一般只出現 IIS 6.0 中,因為只有 IIS 6.0 採用此設計。一般降低回收時間都可以減緩這種情況發生!有時也是因為網站本身程式錯誤造成的假死!如果上述方法不能徹底解決,建議關閉錯誤保護功能試試!
- 經典 ASP 常見缺陷:
- 未釋放 COM 物件 (
Set obj = Nothing 遺漏) → 記憶體/句柄洩漏。
- 資料庫連線未關閉/未歸還連線池 (
conn.Close / Set conn = Nothing)。
- 無限迴圈/遞迴邏輯錯誤導致請求永不結束。
- 大量字串串接 (
str = str & "...") 導致記憶體碎片化,改用 Response.Write 串流輸出或陣列 Join。
- 排查工具:
DebugDiag (抓取掛起進程 Dump 分析)、PerfMon (ASP Requests Queued/Executing/Rejected、Process\Private Bytes/Handle Count)、LogParser 分析 IIS 日誌找出高耗時/高錯誤率 ASP 頁面。
總結:從症狀治療到架構治本
IIS 6.0 應用程式集區回收機制本意是保護穩定性,但單一集區承載過多異質網站時,回收衝突與資源爭用反成禍源。「一池一業務、大站獨享、回收排程錯峰、記憶體預算分配、快速失敗保護」 五大原則,將共享主機環境從「脆弱共生」轉化為「彈性隔離」。配合程式碼層面資源管理規範與持續監控,徹底根治 ASP 假死頑疾。