从应用程序调用 Web 服务时 ASP.NET 问题

本文可帮助解决从应用程序调用 Web 服务时发生的Microsoft ASP.NET 问题。

原始产品版本:  ASP.NET
原始 KB 编号:   821268

症状

从应用程序调用 Web 服务时,ASP.NET 争用、性能不佳和死锁。 客户端可能会报告请求停止响应或需要很长时间来执行。 如果怀疑死锁,可能会回收工作进程。

调用 方法时,您可能会收到以下异常 HttpWebRequest.GetResponse 错误消息:

"System.InvalidOperationException:ThreadPool 对象中没有足够的可用线程来完成该操作。"

您还可以在浏览器中收到以下异常错误消息:

"HttpException (0x80004005) :请求已过。

备注

本文还适用于直接 HttpWebRequest 提出请求的应用程序。

原因

出现此问题的原因 ASP.NET 限制工作线程数和调用可用于执行请求的完成端口线程数。

通常,对 Web 服务的调用使用一个工作线程来执行发送请求的代码,并使用一个完成端口线程从 Web 服务接收回调。 但是,如果请求已重定向或需要身份验证,则调用可能使用两个工作线程和两个完成端口线程。 因此,当同时发生多个 Web 服务调用时,可以耗尽 ThreadPool 托管资源。

例如,假设 限制为 10 个工作线程,并且所有 10 个工作线程当前正在执行等待执行回调 ThreadPool 的代码。 回调永远不会执行,因为排队到 的任何工作项将被阻止,直到 ThreadPool 线程可用。

另一个潜在的争用源 maxconnection 是命名空间用于 System.Net 限制连接数的参数。 通常,此限制将正常工作。 但是,如果许多应用程序尝试同时向单个 IP 地址提出多个请求,则线程可能必须等待可用连接。

解决方案

若要解决这些问题,您可以调整Machine.config 文件中以下 参数,以最适合您的情况:

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

若要成功解决这些问题,请执行下列操作:

  • 将可以同时 ASP.NET 的请求数限制为每个 CPU 大约 12 个。
  • 允许 Web 服务回调自由使用 中的线程 ThreadPool
  • 为参数选择适当的 maxconnections 值。 根据使用的 IP 地址和 AppDomains 的数量进行选择。

备注

建议将请求数 ASP.NET CPU 限制为 12 个,这一点有点随意。 但是,已证明此限制适用于大多数应用程序。

MaxWorkerThreads 和 maxIoThreads

ASP.NET 使用下列两个配置设置来限制使用的最大工作线程数和完成线程数:

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

maxWorkerThreads参数和 maxIoThreads 参数隐式乘以 CPU 数。 例如,如果您有两个处理器,则最大工作线程数为 * maxWorkerThreads 2。

MinFreeThreads 和 minLocalRequestFreeThreads

ASP.NET 还包含以下配置设置,这些设置确定启动远程请求或本地请求必须可用的工作线程数和完成端口线程数:

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

如果没有足够的线程可用,请求将排入队列,直到有足够的线程可用于提出请求。 因此 ASP.NET 请求数不会超过以下数量:

(CPU maxWorkerThreads * 的数量) - minFreeThreads

备注

minFreeThreads参数和 minLocalRequestFreeThreads 参数不隐式乘以 CPU 数。

MinWorkerThreads

ASP.NET 还包含以下配置设置,该设置确定可以立即为远程请求提供服务的工作线程数。

<processModel minWorkerThreads="1">

创建由此设置控制的线程的速度比从公共语言运行时 (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 ,可能还必须修改 processModel responseDeadlockInterval 参数设置。

建议

本节中建议的设置可能并非适用于所有应用程序。 但是,以下其他信息可以帮助您进行适当的调整。

如果要从每个 ASPX 页对单个 IP 地址进行一次 Web 服务调用,Microsoft 建议您使用以下配置设置:

  • 将 参数和 maxWorkerThreads 参数的值 maxIoThreads 设置为 100
  • 将参数的值设置为 maxconnection 12 * N (其中 N 是已设置的 CPU) 。
  • 将 参数的值 minFreeThreads 设置为 88 * N,minLocalRequestFreeThreads 参数设置为 76 * N
  • 将 的值设置为 minWorkerThreads 50。 请记住 minWorkerThreads ,默认情况下不在配置文件中。 必须添加它。

其中一些建议涉及涉及服务器上 CPU 数量的简单公式。 表示公式中 CPU 数的变量是 N

对于这些设置,如果启用了超线程,则必须使用逻辑 CPU 的数量,而不是物理 CPU 的数量。 例如,如果具有一个启用了超线程的四处理器服务器,则公式中的 N 值将为 8 而不是 4。

备注

使用此配置时,最多可以同时执行每个 CPU ASP.NET 12 个请求,因为 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 状态代码) 。
  • 请求需要身份验证。
  • 请求来自多个 AppDomains。

在这些情况下,建议对 参数使用较低的值,对参数和 参数使用较高的 maxconnection minFreeThreads minLocalRequestFreeThreads 值。

详细信息

有关详细信息,请参阅提升 ASP.NET性能

如果在 IIS 上遇到性能不佳和争用以及 ASP.NET,请转到以下 Microsoft 博客: