從 ASP.NET 應用程式呼叫 Web 服務時的效能問題

本文提供協助來解決從 Microsoft ASP.NET 應用程式呼叫 Web 服務時所發生的效能問題。

原始產品版本: ASP.NET
原始 KB 編號: 821268

徵狀

當您從 ASP.NET 應用程式呼叫 Web 服務時,可能會遇到爭用、效能不佳和死結。 用戶端可能會回報要求停止回應,或需要很長的時間才能執行。 如果懷疑有死結,可能會回收背景工作進程。

當您呼叫 HttpWebRequest.GetResponse 方法時,可能會收到下列例外狀況錯誤訊息:

「System.InvalidOperationException:ThreadPool 物件中沒有足夠的可用線程可完成作業。」

您也可以在瀏覽器中收到下列例外狀況錯誤訊息:

「HttpException (0x80004005) :要求逾時。」

注意事項

本文也適用於直接提出 HttpWebRequest 要求的應用程式。

原因

發生此問題的原因可能是 ASP.NET 限制呼叫可用來執行要求的背景工作線程和完成埠線程數目。

一般而言,呼叫 Web 服務會使用一個背景工作線程來執行傳送要求的程式代碼,以及一個完成埠線程來接收來自 Web 服務的回呼。 不過,如果要求已重新導向或需要驗證,呼叫可能會使用多達兩個背景工作線程和兩個完成埠線程。 因此,當多個 Web 服務呼叫同時發生時,您可以耗盡 ThreadPool Managed。

例如,假設 ThreadPool 限制為10個背景工作線程,而且所有10個背景工作線程目前正在執行等候回呼執行的程式碼。 回呼永遠無法執行,因為任何排入 ThreadPool 佇列的工作專案都會遭到封鎖,直到有線程可用為止。

另一個潛在的競爭來源是 maxconnection 命名空間用來限制連線數目的參數 System.Net 。 一般而言,此限制會如預期般運作。 不過,如果許多應用程式同時嘗試對單一IP位址提出許多要求,線程可能必須等候可用的連線。

解決方案

若要解決這些問題,您可以調整 Machine.config 檔案中的下列參數,以最符合您的情況:

  • maxWorkerThreads
  • minWorkerThreads
  • maxIoThreads
  • minFreeThreads
  • minLocalRequestFreeThreads
  • maxconnection
  • executionTimeout

若要成功解決這些問題,請採取下列動作:

  • 將可同時執行的 ASP.NET 要求數目限制為每個 CPU 大約 12 個。
  • 允許 Web 服務回呼自由使用 中的 ThreadPool線程。
  • 為參數選取適當的值 maxconnections 。 根據您選取的IP位址數目和使用的AppDomain數目。

注意事項

將每個 CPU 的 ASP.NET 要求數目限制為 12 的建議有點任意。 不過,這項限制已證明適用於大部分的應用程式。

MaxWorkerThreads 和 maxIoThreads

ASP.NET 使用下列兩個組態設定來限制所使用的背景工作線程和完成線程數目上限:

<processModel maxWorkerThreads="20" maxIoThreads="20">

參數 maxWorkerThreadsmaxIoThreads 參數會隱含地乘以CPU數目。 例如,如果您有兩個處理器,則背景工作線程的最大數目為 2 * maxWorkerThreads

MinFreeThreads 和 minLocalRequestFreeThreads

ASP.NET 也包含下列組態設定,可決定必須有多少個背景工作線程和完成埠線程才能啟動遠端要求或本機要求:

<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">

如果沒有足夠的線程可用,要求會排入佇列,直到有足夠的線程可以自由提出要求為止。 因此,ASP.NET 不會同時執行超過下列數目的要求:

maxWorkerThreads (* CPU) 數目 -minFreeThreads

注意事項

參數 minFreeThreadsminLocalRequestFreeThreads 參數不會隱含地乘以CPU數目。

MinWorkerThreads

ASP.NET 也包含下列組態設定,可決定可立即提供多少個背景工作線程來服務遠端要求。

<processModel minWorkerThreads="1">

與從 Common Language Runtime (CLR 建立的背景工作線程相比,此設定所控制的線程建立速度快得多,) 默認線程微調功能。

此設定可讓 ASP.NET 服務要求,這些要求可能會因為後端伺服器的慢速、來自用戶端的要求突然暴增,或類似會導致佇列中的要求數目突然增加而突然填滿 ASP.NET 要求佇列。

參數的 minWorkerThreads 預設值為 1。 建議您將 參數的 minWorkerThreads 值設定為下列值:

minWorkerThreads = maxWorkerThreads / 2

根據預設, minWorkerThreads 參數不存在於 Web.config 檔案或 Machine.config 檔中。 此設定會隱含地乘以CPU數目。

Maxconnection

參數 maxconnection 會決定可以對特定IP位址建立多少連線。 參數的顯示方式如下:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://65.53.32.230" maxconnection="12">
</connectionManagement>

如果應用程式的程式代碼依主機名稱而非IP位址參考應用程式,參數應該如下所示:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname" maxconnection="12">
</connectionManagement>

最後,如果應用程式裝載於 80 以外的埠上,參數必須在 URL 中包含非標準埠,如下所示:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname:8080" maxconnection="12">
</connectionManagement>

本文稍早討論的參數設定全都在程式層級。 不過, maxconnection 參數設定會套用至 AppDomain 層級。 根據預設,因為此設定適用於AppDomain層級,所以您最多可以從進程中的每個AppDomain建立兩個連線到特定IP位址。

ExecutionTimeout

ASP.NET 使用下列組態設定來限制要求運行時間:

<httpRuntime executionTimeout="90"/>

您也可以使用 Server.ScriptTimeout 屬性來設定此限制。

注意事項

如果您增加 參數的 executionTimeout 值,可能也必須修改 processModelresponseDeadlockInterval 參數設定。

建議

本節中建議的設定可能不適用於所有應用程式。 不過,下列其他資訊可協助您進行適當的調整。

如果您要從每個 ASPX 頁面對單一 IP 位址進行一次 Web 服務呼叫,Microsoft 建議您使用下列組態設定:

  • 將參數和參數的maxWorkerThreadsmaxIoThreads值設定為100
  • 將參數的 maxconnection 值設定為 12*N (其中 N 是您) 的 CPU 數目。
  • 將 參數的 minFreeThreads 值設定為 88*N ,並將 minLocalRequestFreeThreads 參數設定為 76*N
  • 將的 minWorkerThreads 值設定為 50。 請記住, minWorkerThreads 預設不在組態檔中。 您必須新增它。

其中一些建議牽涉到涉及伺服器上CPU數目的簡單公式。 代表公式中 CPU 數目的變數為 N

針對這些設定,如果您已啟用超線程,則必須使用邏輯 CPU 數目,而不是實體 CPU 數目。 例如,如果您有啟用超線程的四處理器伺服器,則公式中的 N 值會是 8 而不是 4

注意事項

當您使用此設定時,每個CPU最多可以同時執行12個 ASP.NET 要求,因為100-88=12。 因此,至少有 88*N 個背景工作線程和 88*N 個完成埠線程可供其他用途 (,例如 Web 服務回呼) 。

例如,您有一部伺服器,其中已啟用四個處理器和超線程。 根據這些公式,您會針對本文所述的組態設定使用下列值。

<system.web>
    <processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50"/>
    <httpRuntime minFreeThreads="704" minLocalRequestFreeThreads="608"/>
</system.web>
<system.net>
    <connectionManagement>
        <add address="[ProvideIPHere]" maxconnection="96"/>
    </connectionManagement>
</system.net>

此外,當您使用此設定時,每個 AppDomain 的每個 IP 位址每個 CPU 可使用 12 個連線。 因此,在下列案例中,當要求正在等候連線,且 ThreadPool 未耗盡 時,很少會發生競爭:

  • Web 只會裝載一個應用程式 (AppDomain) 。
  • ASPX 頁面的每個要求都會提出一個 Web 服務要求。
  • 所有要求都位於相同的IP位址。

不過,當您使用此設定時,涉及下列其中一項的案例可能會使用太多連線:

  • 要求會傳送至多個IP位址。
  • 要求會重新導向 (302 狀態代碼) 。
  • 要求需要驗證。
  • 要求來自多個 AppDomain。

在這些案例中,最好針對 參數使用較低的值 maxconnection ,並針對 minFreeThreads 參數和 minLocalRequestFreeThreads 參數使用較高的值。

其他相關資訊

如需詳細資訊,請 參閱改善 ASP.NET 效能

如果您與 ASP.NET 一起在 IIS 上遇到效能不佳和爭用,請移至下列 Microsoft 部落格: