.NET应用程序性能优化

1、asp.net进程配置优化

asp.net进程模型进行一些进程级别设置,比如asp.net使用多少线程,超时时间,多少请求等待输入输出工作的完成等等。默认情况下有很多限制。现在硬件越来越便宜,G级内存的服务器普遍存在,所以现在进程配置的优化可以得到更多的系统资源和扩展。

Asp.net 1.1的mashine.config配置是这样的

<!--

        processModel Attributes:

          enable="[true|false]" - Enable processModel

          timeout="[Infinite | HH:MM:SS] - Total life of process, once expired process is shutdown and a new process is created

          idleTimeout="[Infinite | HH:MM:SS]" - Total idle life of process, once expired process is automatically shutdown

          shutdownTimeout="[Infinite | HH:MM:SS]" - Time process is given to shutdown gracefully before being killed

          requestLimit="[Infinite | number]" - Total number of requests to serve before process is shutdown

          requestQueueLimit="[Infinite | number]" - Number of queued requests allowed before process is shutdown

          restartQueueLimit="[Infinite | number]" - Number of requests kept in queue while process is restarting

          memoryLimit="[number]" - Represents percentage of physical memory process is allowed to use before process is recycled

          webGarden="[true|false]" - Determines whether a process should be affinitized with a particular CPU

          cpuMask="[bit mask]" - Controls number of available CPUs available for ASP.NET processes (webGarden must be set to true)

          userName="[user]" - Windows user to run the process as.

                      Special users: "SYSTEM": run as localsystem (high privilege admin) account.

                                     "machine": run as low privilege user account named "ASPNET".

                      Other users: If domain is not specified, current machine name is assumed to be the domain name.

          password="[AutoGenerate | password]" - Password of windows user. For special users (SYSTEM and machine), specify "AutoGenerate".

          logLevel="[All|None|Errors]" - Event types logged to the event log

          clientConnectedCheck="[HH:MM:SS]" - Time a request is left in the queue before ASP.NET does a client connected check

          comAuthenticationLevel="[Default|None|Connect|Call|Pkt|PktIntegrity|PktPrivacy]" - Level of authentication for DCOM security

          comImpersonationLevel="[Default|Anonymous|Identify|Impersonate|Delegate]" - Authentication level for COM security

          responseDeadlockInterval="[Infinite | HH:MM:SS]" - For deadlock detection, timeout for responses when there are executing requests.

          maxWorkerThreads="[number]" - Maximum number of worker threads per CPU in the thread pool

          maxIoThreads="[number]" - Maximum number of IO threads per CPU in the thread pool

          serverErrorMessageFile="[filename]" - Customization for "Server Unavailable" message

          When ASP.NET is running under IIS 6 in native mode, the IIS 6 process model is

          used and settings in this section are ignored.  Please use the IIS administrative

          UI to configure things like process identity and cycling for the IIS

          worker process for the desired application         

        -->

        <processModel

            enable="true"

            timeout="06:20:00"

            idleTimeout="Infinite"

            shutdownTimeout="0:00:05"

            requestLimit="Infinite"

            requestQueueLimit="5000"

            restartQueueLimit="10"

            memoryLimit="60"

            webGarden="false"

            cpuMask="0xffffffff"

            userName="machine"

            password="AutoGenerate"

            logLevel="Errors"

            clientConnectedCheck="0:00:05"

            comAuthenticationLevel="Connect"

            comImpersonationLevel="Impersonate"

            responseDeadlockInterval="00:03:00"

            maxWorkerThreads="150"

            maxIoThreads="80"

        />

asp.net 2.0的mashine.config的配置是这样的:

<system.web>

    <processModel autoConfig="true" /> 

</system.web>

你应该改变这样的配置,用一些值设置不同的属性来定制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"

   asyncOption="20"

   maxAppDomains="2000"

/>

除了下面的值外都是一些默认值:

maxWorkerThreads:默认每个进程是20个线程。在双核的服务器上,系统会分配40个线程给asp.net,这就意味着asp.net在双核服务器上同时可以处理40个并发请求。为了给asp.net的每个进程增加线程,我曾经设置过100.如果你的应用的CPU强劲而且有更多的请求需要,你可以设置这个属性。特别是你的网络就用使用了大量的webservice或者上传/下载大量数据这些不会把压力转到CPU上的时候。当asp.net用完了所有的线程,它会停止接收更多的响应。请求会排成队列等待直到其它工作中的线程被释放。这种情况经常发生在网站接收到超出预期的点击的时候,这种情况下,如果你有备用的CPU,请增加进程的线程数量。

maxIOThreads:默认是20个。双核服务器中系统会提供40个I/O线程给ASP.net.I/O请求可以用于网站的文件读写,数据库读取,webservice调用,http请求等等。你可以把它设置的更高一点,特别是在你的网站做并发的上传/下载和webservice调用的时候。

minWorkerThreads:当asp.net*工作线程低于这个值时,asp.net会推送一些请求进入队列。所以你可以设置一个低值来增加当前的请求数量。当然这个值不能设置的太低,因为网站要做一些后台处理和并行处理,这些工作都是需要一些线程来运行的。

minIOThreads:和minWorkerThreads相当,只不过是针对I/O进程进行的设置。它可以设置的比in case of 低,因为I/O并行处理线程没有什么问题。

memoryLimit:指定最大的内存使用大小。它指定的是占所有系统内存的百分比,是指定系统处理进程时可以使用的最大内存数。如果服务器上只有你自己的网站而且没有其它的使用内存的进程,你可以把它设置的高一些,比如:80.如果你的网站存在内存泄露问题,你最好把这个值设置的低一点,这样泄露的内存不久就会释放出来,这样会保持网站的正常运行。特别是你在使用COM组件造成内存泄露的时候。当然这只是个临时方案,最终你还是要解决这个内存泄露的问题。

除了processModel之外,asp.net还可以设置单一IP最大的请求数量:

<system.net>

  <connectionManagement>

    <add address="*" maxconnection="100" />

  </connectionManagement>

</system.net>

默认是2,这个值太低了。这意味着每一个IP最多只能有两个请求到你的网站,这样会造成请求拥堵。这里设置成了100,当然有必要的话,你可以设置得更高。

http://support.microsoft.com/kb/821268

<httpRuntime minFreeThreads="250" minLocalRequestFreeThreads="250"/>

计算公式 (maxWorkerThreads*number of CPUs)-minFreeThreads

http://blogs.msdn.com/wenlong/archive/2008/04/21/wcf-request-throttling-and-server-scalability.aspx

2、管线最佳优化

一些asp.net默认的HttpModules管理请求的管线并且每一个请求。例如:SessionStateModule拦截每一个请求,分析session cookie 来加载HttpContext中的合适的session.但是并不是所有的Modules都是必需的,比如:如果你不用membership的话,就不用配置FormsAuthentication模块;如果你不用windows身份验证就不用配置WindowsAuthentication,这些模块只是包含在管线里面,为每一个请求执行一些并不是必须的代码。默认的模块定义在machine.config中($WINDOWS$Microsoft.NETFramework$VERSION$CONFIG)

如下所示:

<httpModules>

  <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />

  <add name="Session" type="System.Web.SessionState.SessionStateModule" />

  <add name="WindowsAuthentication"

        type="System.Web.Security.WindowsAuthenticationModule" />

  <add name="FormsAuthentication"

        type="System.Web.Security.FormsAuthenticationModule" />

  <add name="PassportAuthentication"

        type="System.Web.Security.PassportAuthenticationModule" />

  <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule"/>

  <add name="FileAuthorization"type="System.Web.Security.FileAuthorizationModule" />

  <add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule,

                             System.Web.Mobile, Version=1.0.5000.0,

                             Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>

</httpModules>

如果你想去掉这些默认的设置,只需要在你的web.config里加入<remove>节点。

<httpModules>

         <!-- 去除不必要的节点,提高请求速度-->

         <remove name="WindowsAuthentication" />

         <remove name="PassportAuthentication" />

         <remove name="UrlAuthorization" />

         <remove name="FileAuthorization" />

</httpModules>

上面的配置适用于基于数据库的form认证的网站。所以这些节点可以被删除。

3、WCF性能优化参数,对于采用非IIS承载的WCF服务

<runtime>

  <gcServerenabled="true" />

</runtime>

涉及到大量请求的时候,可以考虑使用WCF的 ServiceThrottlingBehavior 属性。

限流“允许开发者限制客户端连接数以及服务的负荷。限流可以避免服务的最大化,以及分配与使用重要资源的最大化。引入限流技术后,一旦超出配置的设置值,WCF就会自动地将等待处理的调用者放入到队列中,然后依次从队列中取出。在队列中等待处理调用时,如果客户端的调用超时,客户端就会获得一个TimeoutException异常。每个服务类型都可以应用限流技术,也就是说,它会影响到服务的所有实例以及服务类型的所有终结点。实现方式是为限流与服务使用的每个通道分发器建立关联。”

限流由ServiceThrottlingBehavior类定义,包括三个重要的属性:MaxConcurrentCalls、MaxConcurrentSessions、MaxConcurrentInstances,它们分别的默认值为16,10和Int.MaxValue

 名称

 说明

 MaxConcurrentCalls

获取或设置一个值,该值指定整个 ServiceHost 中正在处理的最多消息数。

 MaxConcurrentInstances

获取或设置一个值,该值指定服务中可以一次执行的最多 InstanceContext 对象数。

 MaxConcurrentSessions

 获取或设置一个指定 ServiceHost 对象可一次接受的最多会话数的值。

 这里我们设置一下服务的限流行为就可以了。具体如下:

<serviceBehaviors>

        <behavior name="WCFService.WCFServiceBehavior">

          <serviceTimeouts transactionTimeout="00:01:00"/>

          <serviceMetadata httpGetEnabled="true" />

          <serviceDebug includeExceptionDetailInFaults="false" />

          <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>-->

        </behavior>

      </serviceBehaviors>

http://blogs.msdn.com/wenlong/archive/2009/09/06/crack-throttling-debugging-wcf-timeoutexception-for-a-middle-tier-application.aspx

操作系统参数调整

1、 TCP/IP 参数调整

    选项 TcpTimedWaitDelay:

    确定 TCP/IP 可释放已关闭连接并重用其资源前,必须经过的时间。关闭和释放之间的此时间间隔通称 TIME_WAIT 状态或两倍最大段生命周期(2MSL)状态。此时间期间,重新打开到客户机和服务器的连接的成本少于建立新连接。减少此条目的值允许 TCP/IP 更快地释放已关闭的连接,为新连接提供更多资源。如果运行的应用程序需要快速释放和创建新连接,而且由于 TIME_WAIT 中存在很多连接,导致低吞吐量,则调整此参数。 Windows 默认值4分钟,调整到60秒

   选项MaxUserPort

   确定在应用程序从系统请求可用用户端口时,TCP/IP 可指定的最高端口号。 默认            值是1024-5000。调整到12000

2、 数据库连接池参数调整

   连接池减少新连接需要打开的次数。 池进程保持物理连接的所有权。 通过为每个给定的连接配置保留一组活动连接来管理连接。 只要用户在连接上调用 Open,池进程就会检查池中是否有可用的连接。 如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。 应用程序对该连接调用 Close 时,池进程会将连接返回到活动连接池集中,而不是真正关闭连接。 连接返回到池中之后,即可在下一个 Open 调用中重复使用。

   只有配置相同的连接可以建立池连接。 ADO.NET 同时保留多个池,每个配置一个池。 连接由连接字符串以及 Windows 标识(在使用集成的安全性时)分为多个池。 还根据连接是否已在事务中登记来建立池连接。

池连接可以显著提高应用程序的性能和可缩放性。 默认情况下,ADO.NET 中启用连接池。除非显式禁用,否则,连接在应用程序中打开和关闭时,池进程将对连接进行优化。 还可以提供几个连接字符串修饰符来控制连接池的行为。

在初次打开连接时,将根据完全匹配算法创建连接池,该算法将池与连接中的连接字符串关联。 每个连接池都与一个不同的连接字符串相关联。 打开新连接时,如果连接字符串并非与现有池完全匹配,将创建一个新池。 按进程、按应用程序域、按连接字符串以及(在使用集成的安全性时)按 Windows 标识来建立池连接。 连接字符串还必须是完全匹配的;按不同顺序为同一连接提供的关键字将分到单独的池中。

如果 MinPoolSize 在连接字符串中未指定或指定为零,池中的连接将在一段时间不活动后关闭。 但是,如果指定的 MinPoolSize 大于零,在 AppDomain 被卸载并且进程结束之前,连接池不会被破坏。 非活动或空池的维护只需要最少的系统开销。

连接池是为每个唯一的连接字符串创建的。 当创建一个池后,将创建多个连接对象并将其添加到该池中,以满足最小池大小的要求。 连接根据需要添加到池中,但是不能超过指定的最大池大小(默认值为 100)。 连接在关闭或断开时释放回池中。

在请求 SqlConnection 对象时,如果存在可用的连接,将从池中获取该对象。 连接要可用,必须未使用,具有匹配的事务上下文或未与任何事务上下文关联,并且具有与服务器的有效链接。

连接池进程通过在连接释放回池中时重新分配连接,来满足这些连接请求。 如果已达到最大池大小且不存在可用的连接,则该请求将会排队。 然后,池进程尝试重新建立任何连接,直到到达超时时间(默认值为 15 秒)。 如果池进程在连接超时之前无法满足请求,将引发异常。

您尝试在 IIS 6.0 中启动工作进程时,收到 2269 事件消息

http://support.microsoft.com/?kbid=896286

服务器无法分配系统页面缓冲池中的内存

http://support.microsoft.com/kb/312362

在 HTTP API 中记录的错误

http://support.microsoft.com/kb/820729/zh-cn

http://blogs.msdn.com/david.wang/archive/2005/09/21/HOWTO-Diagnose-IIS6-failing-to-accept-connections-due-to-Connections-Refused.aspx