前情提要
- 實務上的專案遭受 DDos 攻擊
- DB TimeOut
- Redis TimeOut
- 主程式沒有死,但是 Elmah 出現大量Exception
錯誤資訊

Redis的錯誤記錄
錯誤1.
1 | Timeout performing SETEX Cache:Key:06f305de-f163-4d49-8b98-d8bc51edf7d8, |
錯誤2.
1 | StackExchange.Redis.RedisConnectionException |
錯誤3.
1 | No connection is available to service this operation: |
錯誤4.
1 | UnableToResolvePhysicalConnection on GET |
SQL Server 錯誤記錄
1 | A transport-level error has occurred when receiving results from the server. |
錯誤原因
- CLR 建立執行緒需要時間 , 一秒鐘最多只能建立兩條 Thread 註一
- 瞬間的 Request 量超過 ThreadPool 中的 Thread 數量
- ThreadPool 建立 Thread 中 , 仍持續有 Request 進來引發錯誤
- 因為我的測試環境有四核心,依文件所說
實驗流程
建立監視器
參考 How To: Monitor the ASP.NET Thread Pool Using Custom Counters- 建立一個 console 專案, MyAspNetThreadCounters
- 編譯並執行 console 專案
- 開啟
Regedit.exe檢查HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services應包含以下值
1
2
3
4
5
6Available Worker Threads
Available IO Threads
Max Worker Threads
Max IO Threads
Min Worker Threads
Min IO Threads建立ASP.NET專案
開啟
perfmon.exe新增計數器 , 選取我們自定義的MyAspNetThreadCounters連結網頁
localhost\StartWebApp.aspx以啟動網站,可以得到以下數據1
2
3
4
5
6MaxWorkerThreads:32767.
MaxIOThreads:1000.
MinWorkerThreads:4.
MinIOThreads:4.
AvailableWorker:32766.
AvailableIO:1000.執行大量 redis 連線,觀察結果 AvailableWorker Threads 會往下掉,
故推斷 redis connection 是透過 Worker Threads 建立.重現錯誤, 執行大量的 sleep 頁面,透過這種方式搶佔IIS的執行緒.

再執行大量 redis 連線, 用以重現錯誤

程式碼
MyAspNetThreadCounters
1 | using System; |
Global.asax
1 | public class Global : System.Web |
1 | using System; |
StartWebApp.aspx
1 | protected void Page_Load(object sender, EventArgs e) |
Sleep.aspx
1 | void Page_Load(Object sender, EventArgs e) |
StackExchange.Redis 源碼
1 | private static int GetThreadPoolStats(out string iocp, out string worker) |
環境與工具
- Visual Studio 2015 Professional UPDATE 3
- Windows 10
- .NET Framework 4.5
- StackExchange.Redis 1.0.481
- CPU
Intel® Core™ i7-5500U四核心
官方說明
- 爭用、 效能不佳、 和死結 (deadlock) 當您從 ASP.NET 應用程式呼叫 Web 服務
- machine.config
1 | <system.web> |
建議的設定值
1 | <system.web> |
.NET 官方文件的預設值與建議值
| 名稱 | 預設值 | 建議配置 |
|---|---|---|
| maxWorkerThreads | 20 | 32767 / #Cores |
| maxIoThreads | 20 | 32767 / #Cores |
| minWorkerThreads | 1 | maxWorkerThreads/2 |
| minIoThreads | 1 | maxIoThreads / 2 |
| minFreeThreads | 8 | 88*#CPUs |
| minLocalRequestFreeThreads | 4 | 76*#CPUs |
| maxconnection | 2 | 12*CPUs |
| executionTimeout | 90s | 未建議 |
- maxWorkerThreads,minWorkerThreads,maxIoThreads,minIoThreads 設定的數值需要乘上CPU的數量,
例: 4 核心設定 minWorkerThreads 值 20 ,實際上的值為 80
註釋
- ThreadPool 中會有一個 queue , 其中隱含一個半秒機制 , 當 queue 靜止超過半秒 , 就會在 ThreadPool 建立一個新的 Thread
記錄
- ADO.NET 需要使用 Worker Thread
- Redis 需要使用 Worker Thread
參考
- Threading
- Improving ASP.NET Performance
- Programming the Thread Pool in the .NET Framework
- StackExchange.Redis 源碼
- 雲計算之路-阿里雲上:從ASP.NET線程角度對「黑色30秒」問題的全新分析
- How To: Monitor the ASP.NET Thread Pool Using Custom Counters
- http://www.thejoyofcode.com/tuning_the_threadpool.aspx
- https://gist.github.com/JonCole/e65411214030f0d823cb
- https://blogs.msdn.microsoft.com/carloc/2009/02/19/minworkerthreads-and-autoconfig/
(fin)