IIS處理併發請求時出現的問題及解決

原文連接:http://www.cnblogs.com/hgamezoom/p/3082538.htmlhtml

一個ASP.NET項目在部署到生產環境時,當用戶併發量達到200左右時,IIS出現了明顯的請求排隊現象,發送的請求都進入等待,沒法及時響應,系統基本處於不可用狀態。因經驗不足,花了不少時間精力解決這個問題,本文記錄了我查找問題的過程和最後解決方案,供你們參考。web

 

軟硬件環境:服務器

IBM刀片服務器,Intel至強處理器,4物理核,16個邏輯核心,內存32G併發

Windows Server2008 Enterprise R2, ASP.NET 4.0 Webform  IIS7.5  集成模式佈局

 

當發現請求明顯延遲,沒有被即時處理的現象,首先就要查看Windows自帶的性能日誌Performance Monitor。性能

因爲我注意到只有對於.aspx或.ashx的請求才會延遲,而.htm或.jpg文件都是即時響應的,因此很明顯問題出在ASP.NET上,因而我選擇了性能監視器中的ASP.NET 4.0中的2個主要計數器:Requests Current(當前請求數), Requests Queued(被排隊的請求數)進行觀察。經過觀察發現,當前請求數達到200左右時,被排隊的請求數就從0開始上升,一直到50左右,若是請求數繼續上升,則被排隊數也隨之上升。當被排隊的請求數>0時,就意味着這個時候去訪問任何.aspx頁面,頁面都會處於長時間等待中,沒有任何響應,直到IIS處理完了其餘請求,纔會開始處理隊列中的請求。也就是說,當排隊數長期>0時,系統基本處於不可用的狀態。測試

因爲這個系統的頁面佈局比較複雜,採用了大量的Ajax+.ashx的方式,將內容分批展現在頁面上,因此對服務器的請求總數會比傳統aspx模式來的多一些,一個頁面所有加載完畢可能須要5-10秒,但我想這不該該是形成問題的主要緣由,就算系統性能較差,IIS也應該足以承受這麼小的併發量的。網站

爲探究究竟是系統寫的有問題,仍是IIS自己的問題,我拋開咱們的系統,寫了一個簡單的頁面,就一個aspx文件,page_load裏sleep 10秒。假設這就是一個性能比較差的網站,每一個頁面都要10秒才能展示,我將其部署在IIS上測試其性能,我使用的是Microsoft Web Application Stress Tool,模擬發起80個線程,每一個鏈接有4個Socket,總共至關於320個併發請求。線程

測試開始後,能夠從下圖中看到,當前請求數馬上攀升到300左右(圖中紅線),而後隊列中的請求數也上升到300左右(圖中綠線),就是說在300個併發請求下,幾乎全部的請求都被排隊了,系統基本不可用,經過簡單的測試,這個問題已經得以重現了。設計

 

隨着時間推移,發現綠線慢慢減小,從300降低到100多,就是系統可用性漸漸提升,有一部分用戶能夠正常使用,但大部分還在排隊。

 

過了6,7分鐘,隊列中的請求數降低到0左右,並有一些小幅波動。這個時候大部分請求能夠被正常處理了。 按照這個現象分析的話,應該是IIS發現有大量請求在隊列中,就會試圖增長處理線程數以知足要求,可是增加速度有些緩慢。

 

那是否是系統通過了6,7分鐘的適應期以後,之後就一直能夠在這個併發量下穩定運做了呢?事實並不是如此。我將壓力測試停了幾秒,當服務器的請求數降爲0之後,再從新開啓320個請求的測試,IIS如何表現?從下圖能夠看到,只要請求數有明顯上升,則等待隊列又開始達到最高值,而後緩慢降低,重複上面的過程。總結下來就是,當出現較大併發時,IIS的處理請求能力徹底跟不上,須要很長時間才能開出足夠的線程。

 

 

而後我作了一個測試,看看IIS默認狀況到底能承受多少請求而不排隊?彷佛是在100個併發左右,表現尚可,未出現排隊。

 

當200個左右就不行了。

 

而後我將測試程序從sleep10秒改爲3秒,對於一個應用系統來講,頁面平均3秒處理時間的性能該還算比較正常了。但惋惜的是,排隊現象與處理時間並沒有太大關係,排隊仍然很嚴重。

 

針對以上問題,查閱了相關資料,是否出現排隊是和應用程序池的可用線程有關,經過2個方法能夠查看系統總線程數和當前可用線程數。

ThreadPool.GetAvailableThreads( out availableWorker, out availableIO);

ThreadPool.GetMaxThreads(out maxWorker, out maxIO);

在隊列請求數達到120左右時,經過此方法,獲得maxWorker=1600,而availableWorker=1472

由於服務器是16核的,ASP.NET4.0默認每核可使用100個線程,因此maxWorker是1600,1600-120=1480,大體相等。

就是說當前有120個線程被用來處理請求,還有1400多個處於空閒。關鍵問題就是爲何這些空閒線程沒有被及時啓用?

 

ASP.NET提供的線程配置參數中,有一個參數是很是重要,可是可能被你們忽略的,就是minWorkerThreads。

意指最小工做線程,根據咱們以上的測試結果,IIS託管線程啓動很是慢,微軟也認識到了這個問題,因此提供此參數用於設置正常狀況下的最小工做線程數。好比咱們系統白天的併發在200-300之間,則能夠設置最小線程爲300,這樣系統響應速度能夠大幅提升。

據此,我對配置文件(machine.config)進行了以下修改。注意都是針對單個CPU的,系統會自動乘以邏輯CPU的數量。

<system.web>
<processModel autoConfig="false" maxWorkerThreads="200" minWorkerThreads="50" />

 至關於最小工做線程設置成了50*16=800。

 

重啓IIS後進行測試,咱們獲得瞭如下結果:

 

 

能夠看到,因爲設置了合理的最小工做線程數,使得IIS無需不斷建立新線程來處理請求,系統的響應能力已能夠知足併發要求。

 

除此以外,在IIS6以後引入了一個新功能叫Web Garden,其設計目的是爲了在CPU佔用較低,可是併發請求數比較多的狀況下,提高服務器性能。這正符合我當前的狀況,因而我啓用了Web Garden,將工做進程數從1調整到5,在任務管理器中能夠看到w3wp進程從原來的1增長到了5,而後從新測試。

 

一樣的320個請求下,能夠看到除了一開始的幾秒出現了一些排隊,後面基本上表現良好,沒有請求進入隊列。

 

經過以上兩種方式,均可以有效解決本文開頭提出的問題。但Web Garden是工做在多進程模式下,若是應用中用到了依賴進程的Session和Cache等對象都必須另想辦法,不能保存在服務器內存中,並且Web Garden的多個進程切換時會有上下文複製,其資源消耗相對單進程要大,這些是須要考慮的因素。

相關文章
相關標籤/搜索