首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

Session_End 事件導致 CPU 定期飆升的效能疑雲排查實錄

     編輯:關於ASP.NET

高流量網站(日 PV 500 萬、獨立 IP 3 萬)在 Windows 2003 + ASP.NET + SQL Server 2000 環境下,出現詭異現象:記憶體穩定 218MB,CPU 閒置僅 5%,但**每 20 秒固定飆升至 30%-50%**。重新部署後前 30 分鐘正常,之後開始周期性飆升。本文記錄完整排查過程,揭示 `Session_End` 事件在大量 Session 過期清理時的效能殺手本質。

現象與假設

  • 固定 20 秒週期 → 懷疑定時器或排程任務
  • 程式碼搜尋無 Timer、無 "20" 關鍵字
  • 重新部署後 30 分鐘無問題 → 緩存/Session 累積觸發條件

鎖定 Global.asax 的 Session_End

void Session_End(object sender, EventArgs e) {
    if (Session.SessionID != "") {
        Application.Remove("id" + Session.SessionID);
        Application.Contents.Remove("id" + Session.SessionID);
    }
}

註解掉此段程式碼後重新部署,**CPU 立即恢復平穩**,確認禍首。

深度驗證:記錄 Session_End 觸發頻率

void Session_End(object sender, EventArgs e) {
    if (Session.SessionID != "") {
        string sessionId = Session.SessionID;
        string appContent = Application.Contents["id" + Session.SessionID].ToString();
        SessionLog.Insert(sessionId, appContent, DateTime.Now); // 寫入資料庫記錄
        Application.Remove("id" + Session.SessionID);
        Application.Contents.Remove("id" + Session.SessionID);
    }
}

半小時後查詢資料庫,發現觸發時間高度集中在 **00-01秒、20-21秒、40-41秒** 等區間,每次 **70-120 條記錄**,完美吻合 20 秒週期。

根因分析

  1. ASP.NET `InProc` 模式下,Session 過期由內部計時器掃描清理
  2. 預設掃描間隔約 20 秒(非公開實作細節)
  3. 每次掃描發現大量過期 Session → 批次觸發 `Session_End`
  4. 事件中執行 `Application.Remove`(鎖定全域 Application 狀態)+ 寫資料庫 → 鎖競爭 + I/O 擁塞 → CPU 飆升
  5. 隨時間 Session 累積越多,每次清理負擔越重,故部署 30 分鐘後才發作

解決方案與最佳實踐

方案優點缺點/注意
移除 Session_End 邏輯最徹底、零成本失去 Session 結束時的清理機會
改用 StateServer / SQLServer Session 模式不觸發 Session_End、支援 Web Farm序列化開銷、需額外服務
非同步批次清理不阻塞請求執行緒實作複雜、需佇列機制
縮減 Session Timeout減少同時存活 Session 數影響用戶體驗
Application 改用 ConcurrentDictionary無鎖高效能.NET 4.0+ 才支援

經驗總結

  • Session_End 非即時觸發,而是批次排程執行,高併發下極易成效能瓶頸
  • Application 物件鎖定範圍大,頻繁 `Remove` 會嚴重阻塞其他請求
  • InProc 模式不適合大流量網站,建議改用分散式 Session 或無狀態設計
  • 效能問題必須用數據說話,資料庫記錄法精準定位觸發頻率與數量

此案例為經典 ASP.NET 效能調優教材,提醒開發者重新審視 `Global.asax` 中看似無害的清理邏輯,在高併發場景下可能成為隱形殺手。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved