提升 ASP.NET、WCF 和桌面客户端性能和可扩展性的快速方法






4.89/5 (44投票s)
通过对 machine.config 和 IIS 进行一些简单的配置更改,您可以为 Web 应用程序带来显著的性能提升。这些更改简单无害,但在可扩展性方面会产生很大影响。
引言
通过对 machine.config 和 IIS 进行一些简单的配置更改,您可以为 Web 应用程序带来显著的性能提升。这些更改简单无害,但在可扩展性方面会产生很大影响。通过调整 system.net
设置,您可以增加从服务器托管的服务以及桌面计算机发出的并行调用数量,从而提高可扩展性。通过更改 WCF 节流配置,您可以增加 WCF 可以接受的并发调用数量,从而最大限度地利用硬件资源。通过更改 ASP.NET 进程模型,您可以增加您的网站可以服务的并发请求数量。最后,通过启用 IIS 缓存和动态压缩,您可以极大地提高浏览器上的页面下载速度以及应用程序的整体响应速度。
System.net 设置
默认情况下,system.net
允许每个 IP 地址有两个并发连接。这意味着在 Web 服务器上,如果它调用另一台服务器上的 WCF 服务或对特定服务器进行任何出站调用,它将只能进行两次并发调用。当您拥有分布式应用程序,并且您的 Web 服务器需要频繁地对另一台服务器进行服务调用时,这会成为最大的瓶颈。

同样,如果您有一个桌面应用程序正在尝试向服务器发出多个 Web 服务调用,客户端计算机 machine.config
中的 system.net
设置将只允许向您的 Web 服务器进行两次并发调用。如果您的应用程序向您的 Web 服务器发出大量并发调用,那么这将成为主要瓶颈。无论您的客户端应用程序和服务器有多快,两次并发调用的限制都会扼杀它。

为了克服这个限制,您必须在 web.config 或 machine.config 中更改 system.net
配置。对于桌面应用程序,您需要将其应用于 app.Config。
<system.net>
<connectionManagement>
<add address="*" maxconnection="100" />
</connectionManagement>
</system.net>
这为所有 IP 地址提供了 100 个并发连接的限制。您可能希望具体指定某个固定 IP 地址或域名。如果您在桌面应用程序上执行此操作,100 个可能过多。最好选择一个适中的值,以防止意外的大量调用涌向 Web 服务器并导致其崩溃。
WCF 节流
就像 system.net
和 system.web
的默认设置在一定程度上阻止您构建高度可扩展的应用程序一样,WCF 的默认配置也非常吝啬。默认情况下,它每个服务只允许 16 个并发调用。此外,如果您使用 wsHttpBinding
并使用会话,则只允许 10 个并发会话。对于如今流行的应用程序来说,这太低了。
对于所有 WCF 设置的最佳总结就是这篇博文。我将重点介绍您应该始终更改的最常见设置。
<serviceBehaviors>
<behavior name="defaultServiceBehavior">
<serviceThrottling maxConcurrentCalls="100"
maxConcurrentInstances="100" maxConcurrentSessions="100" />
以下是这些设置的摘要
maxConcurrentCalls
:定义ServiceHost
的所有服务实例积极处理的最大消息数量。默认值为16
。超出限制的调用将被排队。maxConcurrentInstances
:定义可以同时执行的最大服务实例数量。默认值为Int32.MaxValue
。创建其他实例的请求将被排队,并在低于限制的槽位可用时完成。maxConcurrentSessions
:定义ServiceHost
实例一次可以接受的最大会话数量。默认值为10
。服务将接受超出限制的连接,但只有低于限制的通道是活动的(消息从通道读取)。
同时确保您的服务设置为 InstancePerContext.PerCall
。这确保每个请求都由新线程上的服务新实例处理。
如果您通过 ASP.NET 托管 WCF 服务(例如,使用 WCF REST Starter Kit),那么您会进一步受到 ASP.NET 进程模型更改的限制,您也需要加强这一点。
ASP.NET 进程模型更改
进程模型配置定义了一些进程级别的属性,例如 ASP.NET 使用的线程数量、在超时之前阻塞线程的时间长度、在 I/O 工作完成之前需要等待的请求数量等等。在大多数情况下,默认值过于有限。如今,硬件已经变得相当便宜,双核带千兆内存的服务器已成为常见的选择。因此,可以调整进程模型配置,使 ASP.NET 进程消耗更多系统资源,并从每个服务器获得更好的可扩展性。
标准的 ASP.NET 安装将创建 machine.config,其中包含以下配置
<system.web>
<processModel autoConfig="true" />
您需要调整此自动配置,并为不同属性使用一些特定值,以自定义 ASP.NET 工作进程的工作方式。例如
<processModel
enable="true"
timeout="Infinite"
idleTimeout="Infinite"
shutdownTimeout="00:00:05"
requestLimit="Infinite"
requestQueueLimit="5000"
restartQueueLimit="10"
memoryLimit="60"
webGarden="false"
cpuMask="0xffffffff"
userName="machine"
password="AutoGenerate"
logLevel="Errors"
clientConnectedCheck="00:00:05"
comAuthenticationLevel="Connect"
comImpersonationLevel="Impersonate"
responseDeadlockInterval="00:03:00"
responseRestartDeadlockInterval="00:03:00"
autoConfig="false"
maxWorkerThreads="100"
maxIoThreads="100"
minWorkerThreads="40"
minIoThreads="30"
serverErrorMessageFile=""
pingFrequency="Infinite"
pingTimeout="Infinite"
maxAppDomains="2000"
/>
此处所有值均为默认值,但以下值除外
maxWorkerThreads
- 每个进程默认值为 20。在双核计算机上,将为 ASP.NET 分配 40 个线程。这意味着 ASP.NET 在双核服务器上一次可以处理 40 个请求。我已经将其增加到 100,以便为 ASP.NET 提供每个进程更多的线程。如果您的应用程序不是那么 CPU 密集型,并且可以轻松处理更多每秒的请求,那么您可以增加此值。特别是如果您的 Web 应用程序使用大量 Web 服务调用或下载/上传大量数据,这些操作不会给 CPU 带来压力。当 ASP.NET 耗尽工作线程时,它将停止处理进来的更多请求。请求会进入队列并一直等待,直到工作线程被释放。当站点开始接收比您最初计划的更多的访问量时,通常会发生这种情况。在这种情况下,如果您有闲置的 CPU,请增加每个进程的工作线程数。maxIOThreads
- 每个进程默认值为 20。在双核计算机上,将为 ASP.NET 分配 40 个线程用于 I/O 操作。这意味着 ASP.NET 在双核服务器上一次可以处理 40 个 I/O 请求。I/O 请求可以是文件读/写、数据库操作、 Web 服务调用、 Web 应用程序内部生成的 HTTP 请求等等。因此,如果您的服务器有足够的系统资源来处理更多这些 I/O 请求,您可以将其设置为 100。特别是当您的 Web 应用程序下载/上传数据,或并行调用许多外部 Web 服务时。minWorkerThreads
- 当空闲的 ASP.NET 工作线程数量低于此数字时,ASP.NET 将开始将入站请求放入队列。因此,您可以将此值设置为较低的数字以增加并发请求的数量。但是,不要将其设置为非常低的值,因为 Web 应用程序代码可能需要进行一些后台处理和并行处理,为此它将需要一些空闲的工作线程。minIOThreads
- 与minWorkerThreads
相同,但这是针对 I/O 线程的。但是,您可以将其设置为低于minWorkerThreads
的值,因为 I/O 线程没有并行处理的问题。memoryLimit
- 指定工作进程在 ASP.NET 启动新进程并重新分配现有请求之前可以消耗的总系统内存的百分比。如果您只在专用服务器上运行 Web 应用程序,并且没有其他进程需要 RAM,您可以将其设置为 80 这样的高值。但是,如果您有一个有内存泄漏的应用程序,那么最好将其设置为较低的值,以便在有内存泄漏的进程成为内存占用者之前尽快回收,从而保持您的网站健康。特别是当您使用 COM 组件并有内存泄漏时。然而,这是一个临时解决方案,您当然需要修复泄漏。
我有一个非常受欢迎的文章,介绍了更多 ASP.NET 优化技术。如果您正在构建一个包含许多 AJAX 功能的丰富的 ASP.NET 应用程序,也请阅读它。
启用 IIS 缓存和动态压缩
您可以为静态和动态内容启用 IIS 压缩。动态内容压缩将影响 aspx 和 WCF 服务的输出。

如果您发现“启用动态内容压缩”选项被禁用,那么您需要从 Windows 开始菜单中转到“添加或删除功能”,然后从 IIS 功能中启用 IIS 动态压缩。
您可能需要先在服务器级别启用压缩,然后再在站点级别启用。
监控服务器以解决性能问题
您可以使用 Windows 性能监视器来监视一些关键性能计数器,以识别性能瓶颈。例如,对于托管 WCF 服务的 ASP.NET Web 应用程序,应监视以下计数器。

为了启用 WCF 性能计数器,您需要在 web.config 中添加此项
<system.serviceModel>
<diagnostics performanceCounters="All" />
这将告诉 WCF 将值记录到性能计数器中,以便您可以在性能监视器中看到它们。
WCF 4 中的改进
在 WCF 4 中,默认设置已大大放宽,并经过仔细计算,以在 CPU 和线程之间达到最佳平衡。这是根据 WCF 团队成员的博文的默认配置
在 WCF 4 中,我们修改了这些设置的默认值,以便大多数情况下用户无需更改默认值。以下是主要更改
- MaxConcurrentSessions:默认值为 100 * ProcessorCount
- MaxConcurrentCalls:默认值为 16 * ProcessorCount
- MaxConcurrentInstances:默认值是上述两者的总和,这与之前模式相同。
是的,我们使用“ProcessorCount”作为乘数。因此,在 4 处理器服务器上,MaxConcurrentCalls 的默认值将是 16 * 4 = 64。基本考虑是,当您编写 WCF 服务并使用默认设置时,该服务可以部署到从低端单处理器服务器到高端 24 路服务器的任何系统,而无需更改设置。因此,我们使用 CPU 数量作为乘数。
我们还将 MaxConcurrentSessions 的值从 10 提高到 100。根据客户的反馈,这一更改符合大多数应用程序的需求。
请注意,这些更改仅适用于默认设置。如果您在配置或代码中明确设置了这些设置,系统将使用您提供的值。不会应用“ProcessCount”乘数。
结论
上述性能调整在当今的 Web 应用程序中非常常见,没有它们,您就无法构建一个能够服务数千用户的应用程序。令人惊讶的是,默认配置如此吝啬,以至于公司花费数百美元来调查可以通过上述调整轻松解决的性能和可扩展性瓶颈。