IIS并发连接数及性能优化

如果要查看IIS连接数,最简单方便的方法是通过“网站统计”来查看,“网站统计”的当前在线人数可以认为是当前IIS连接数。然而,“网站统计”的当前在线人数统计时间较长,一般为10分钟或15分钟,再加上统计技术及统计机制的问题,从而会产生或多或少的统计误差。

如果要想知道确切的当前网站IIS连接数的话,最有效的方法是通过windows自带的系统监视器来查看。这正是本文要介绍的方法。

一、     新建IIS并发连接数监控器

1.     运行-->输入“perfmon.msc”

2.     在“系统监视器”图表区域里点击右键,然后点“添加计数器”

 

图一

3.     在“添加计数器”窗口,“性能对象”选择Web Service,“从列表选择计数器”选中Current Connection,“从列表选择实例”选中你要统计的站点,最后点击“添加”按钮

图二

二、     设置完毕

这样,你就可以在“系统监视器”图表区域中看到一条曲线(此曲线你可以设置其颜色和宽度等参数),它就是网站的IIS连接数曲线图了,如图一黄色曲线所示。

需要说明的是,windows系统监视器显示的是即时IIS并发连接数,并非如“网站统计”那里的15分钟内访问人数,所以你会发现IIS并发连接数并不会太多



解决方法:

超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。 
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 

异常详细信息: System.InvalidOperationException: 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。

这是个老问题了!你就查两点:  
  一、看所有open的连接是否都close了。  
  二、如果访问量很大,加上Max Pool Size=512这一句,当然这是要以损失系统性能为代价的!  
  这样以后一定可以解决你的问题!

  解决方案一

我 想原因可能是并发操作。DataReader是独占连接的,就是说你的程序可能设计上有问题。比如说最大连接设100,假设有100个人同时使用 DataReader正在读取数据库内容,那么当第101人读取的时候,连接池中的连接已经没有了,就会出现上面的错误。DataReader是独占连接 的,每个DataReader都要占用一个连接。当然这个情况是偶尔出现的,所以会很长时间出现一次,因为只有同时有超过连接池最大连接数量的并发操作才 会发生。而且你加大并发数量只能暂时缓解问题,如果你加大到200个并发连接,如果有201 人同时操作怎么办?你说了你使用Connection对象的Close()方法,这是不行的,因为Close()方法仅仅是关闭连接,但这个连接没有释 放,还是被这个对象占用,要释放必须使用Connection的Dispose()方法显式释放连接才可以,否则这个对象占用的连接只能等到垃圾收集的情 况下才能被释放。这种情况肯定会出现“超时时间已到”的错误。

解决方法:
  1 修改几个关键页面或访问比较频繁的数据库访问操作,使用DataAdapter和DataSet来获取数据库数据,不要使用DataReader。
  2 在访问数据库的页面上使用数据缓存,如果页面的数据不是经常更新(几分钟更新一次)的话,使用Cache对象可以不用访问数据库而使用缓存中的内容,那么可以大大减少连接数量。
  3 修改代码,把使用Connection对象的地方都在Close()后面加上Dispose()调用。
  4 建议对数据库操作进行大的修改,建立自己的数据库操作代理类,继承System.IDisposable接口,强迫释放资源,这样就不会出现连接数量不够的问题了。

解决方案二

解决方法(*):WEB.config 里面:在数据库连接加 Max Pool Size = 512;server=local;uid=;pwd=;database=2004;Max Pool Size = 512;">一劳永逸。

解决方案三

估计是连接(Connection)对象没有Close。倒是不必Dispose,而DataReader用完后应该关闭,但不关闭也没问题,只是不关闭的话此连接对象就一直不能用,只要你最终关闭了连接对象就不会出问题。  
   
  连接对象在Open后的操作都放在try块中,后面跟一个finally块:conn.Close();


 

经常发生 “数据库连接过多的错误” 这样的错误,但是却又不清楚当前的连接数为多少,大致的总结了几种方法。
1.通过系统的“性能”来查看:
开始->管理工具->性能(或者是运行里面输入 mmc)然后通过

[attach]52716[/attach]

添加计数器添加 SQL 的常用统计 然后在下面列出的项目里面选择用户连接就可以时时查询到数据库的连接数了。
不过此方法的话需要有访问那台计算机的权限,就是要通过windows账户登陆进去才可以添加此计数器。
2.通过系统表来查询:
[code]SELECT * FROM
[Master].[dbo].[SYSPROCESSES] WHERE [DBID]
IN
(
   SELECT
[DBID]
   FROM
[Master].[dbo].[SYSDATABASES]
   WHERE
NAME='databaseName'
)
[/code]

databaseName 是需要查看的数据库,然后查询出来的行数,就是当前的连接数。不过里面还有一些别的状态可以做参考用。

由上面的语句可以看出系统表获取一些连接和活动信息,主要介绍下面的两个系统表:

(1)sprocesses

sysprocesses 表中保存关于运行在 Microsoft® SQL Server™ 上的进程的信息。这些进程可以是客户端进程或系统进程。sysprocesses 只存储在 master 数据库中。

(2)Sysperfinfo

包括一个 Microsoft® SQL Server™ 表示法的内部性能计数器,可通过 Windows NT 性能监视器显示.

 

有人提议说为了获取SQL Server的当前连接数:使用如下SQL:

SELECT COUNT(*) AS CONNECTIONS FROM master..sysprocesses

个人认为这样不对,看看.sysprocesses的login_time列就可看出.

 

另外一个方面是进程不能和连接相提并论,他们是一对一的关系吗,也就是说一个进程就是一个连接?一个连接应该有多个进程的,所以连接和进程之间的关系应该是1:n的.


因为sysprocesses列出的进程包含了系统进程和用户进程,为了得到用户连接,可以使用如下SQL:

SELECT cntr_value AS User_Connections FROM master..sysperfinfo as p
WHERE p.object_name = 'SQLServer:General Statistics' And p.counter_name = 'User Connections'

个人还是认为不对,因为它是一个计数器,可能会累加的.

还有一种方案是利用如下SQL:

select connectnum=count(distinct net_address)-1 from master..sysprocesses

理由是net_address是访问者机器的网卡值,这个总该是唯一的吧.但是看起来得到的是所有时间内的连接数.

希望大家可以给出自己的解决方案.这个问题解决了,相信会有很大的用途.


3.通过系统过程来查询:
[url=http://search.microsoft.com/default.asp?so=RECCNT&siteid=us%2Fdev&p=1&nq=NEW&qu=SP_WHO&IntlSearch=&boolean=PHRASE&ig=01&i=09&i=99]SP_WHO[/url] 'loginName'
loginName 是当然登陆Sql的用户名,一般程序里面都会使用一个username来登陆SQL这样通过这个用户名就能查看到此用户名登陆之后占用的连接了。
如果不写loginName,那么返回的就是所有的连接。

sp_who提供icrosoft® SQL Server™ 用户和进程的信息。可以筛选返回的信息,以便只返回那些不是空闲的进程。

列出所有活动的用户:SP_WHO ‘active’

列出某个特定用户的信息:SP_WHO ‘sa’

4、系统变量

@@CONNECTIONS 返回自上次启动 Microsoft® SQL Server™ 以来连接或试图连接的次数。

@@MAX_CONNECTIONS 返回 Microsoft® SQL Server™ 上允许的同时用户连接的最大数。返回的数不必为当前配置的数值

 


***************连接池和连接数详解**********


连接到数据库服务器通常由几个需要很长时间的步骤组成。 必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次握手,必须分析连接字符串信息,必须由服务器对连接进行身份验证,必须运行检查以便在当前事务中登记,等等。 

实际上,大多数应用程序仅使用一个或几个不同的连接配置。 这意味着在执行应用程序期间,许多相同的连接将反复地打开和关闭。 为了使打开的连接成本最低,ADO.NET 使用称为连接池的优化方法。

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

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

池连接可以显著提高应用程序的性能和可缩放性。 默认情况下,ADO.Net 中启用连接池。除非显式禁用,否则,连接在应用程序中打开和关闭时,池进程将对连接进行优化。 还可以提供几个连接字符串修饰符来控制连接池的行为。 有关更多信息,请参见本主题后面的“使用连接字符串关键字控制连接池”。

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

在以下 C# 示例中创建了三个新的 SqlConnection 对象,但是管理时只需要两个连接池。 注意,根据为 Initial Catalog 分配的值,第一个和第二个连接字符串有所不同。

  复制代码 
using (SqlConnection connection = new SqlConnection(
  "Integrated Security=SSPI;Initial Catalog=Northwind"))
  {
  connection.Open();  
  // Pool A is created.
  }

using (SqlConnection connection = new SqlConnection(
  "Integrated Security=SSPI;Initial Catalog=pubs"))
  {
  connection.Open();  
  // Pool B is created because the connection strings differ.
  }

using (SqlConnection connection = new SqlConnection(
  "Integrated Security=SSPI;Initial Catalog=Northwind"))
  {
  connection.Open();  
  // The connection string matches pool A.
  }
 

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

注意: 
当出现故障转移等错误时,会自动清除池。
 

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

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

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

警告: 
我们强烈建议您在使用完连接后总是将其关闭,以使连接返回到池中。要关闭连接,可以使用 Connection 对象的 Close 或 Dispose 方法,也可以通过在 C# 的 using 语句中或在 Visual Basic 的 Using 语句中打开所有连接。 不是显式关闭的连接可能不会添加或返回到池中。 有关更多信息,请参见 Visual Basic 的using Statement (C# Programmer's Reference)或How to: Dispose of a System Resource。
 
注意: 
不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose。 在终结器中,仅释放类直接拥有的非托管资源。 如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。 有关更多信息,请参见Garbage Collection。
 

移除连接
如果连接长时间空闲,或池进程检测到与服务器的连接已断开,连接池进程会将该连接从池中移除。 注意,只有在尝试与服务器进行通信之后才能检测到断开的连接。 如果发现某连接不再连接到服务器,则会将其标记为无效。 无效连接只有在关闭或重新建立后,才会从连接池中移除。

如果存在与已消失的服务器的连接,那么即使连接池管理程序未检测到已断开的连接并将其标记为无效,仍有可能将此连接从池中取出。 这种情况是因为检查连接是否仍有效的系统开销将造成与服务器的另一次往返,从而抵消了池进程的优势。 发生此情况时,初次尝试使用该连接将检测连接是否曾断开,并引发异常。

清除池
ADO.NET 2.0 引入了清除池的两种新方法: ClearAllPools 和 ClearPool。 ClearAllPools 清除给定提供程序的连接池,ClearPool 清除与特定连接关联的连接池。 如果在调用时连接正在使用,将进行相应的标记。 连接关闭时,将被丢弃,而不是返回池中。

事务支持
连接是根据事务上下文来从池中取出并进行分配的。 除非在连接字符串中指定了 Enlist=false,否则,连接池将确保连接在 Current 上下文中登记。 当连接通过登记的 System.Transactions 事务关闭并返回到池中时,连接将被保留,以便下次使用同一 System.Transactions 事务请求该连接池时,可返回同一连接(如果该连接可用)。如果该连接不可用,则会打开新连接。如果该事务没有可用连接,在该连接打开时,将自动注册该连接。

当连接关闭时,它将被释放回池中,并根据其事务上下文放入相应的子部分。 因此,即使分布式事务仍然挂起,仍可以关闭该连接而不会生成错误。 这样,您就可以在随后提交或中止分布式事务。

使用连接字符串关键字控制连接池
SqlConnection 对象的 ConnectionString 属性支持连接字符串键/值对,可以用于调整连接池逻辑的行为。 有关更多信息,请参见 ConnectionString。

池碎片
池碎片是许多 Web 应用程序中的一个常见问题,应用程序可能会创建大量在进程退出后才会释放的池。 这样,将打开大量的连接,占用许多内存,从而影响性能。

因为集成安全性产生的池碎片
连接根据连接字符串以及用户标识来建立池连接。 因此,如果使用网站上的基本身份验证或 Windows 身份验证以及集成的安全登录,每个用户将获得一个池。 尽管这样可以提高单个用户的后续数据库请求的性能,但是该用户无法利用其他用户建立的连接。 这样还使每个用户至少产生一个与数据库服务器的连接。 这对特定 Web 应用程序结构会产生副作用,因为开发人员需要衡量安全性和审计要求。

因为许多数据库产生的池碎片
许多 Internet 服务提供商在一台服务器上托管多个网站。 他们可能使用单个数据库确认窗体身份验证登录,然后为该用户或用户组打开与特定数据库的连接。 与身份验证数据库的连接将建立池连接,供每个用户使用。 但是,每个数据库的连接存在一个独立的池,因此增加了与服务器的连接数。

这也会对应用程序设计产生副作用。 但是,可以通过一个相对简单的方式避免此副作用,而又不会影响连接 SQL Server 时的安全性。 不是为每个用户或组连接独立的数据库,而是连接到服务器上的相同数据库,然后执行 Transact-SQL USE 语句来切换为所需的数据库。 以下代码段演示入如何创建与 master 数据库的初始连接,然后切换到 databaseName 字符串变量中指定的所需数据库。 

Visual Basic 复制代码 
' Assumes that command is a valid SqlCommand object and that
' connectionString connects to master.
  command.Text = "USE DatabaseName"
Using connection As New SqlConnection(connectionString)
  connection.Open()
  command.ExecuteNonQuery()
End Using
 
C# 复制代码 
// Assumes that command is a SqlCommand object and that
// connectionString connects to master.
command.Text = "USE DatabaseName";
using (SqlConnection connection = new SqlConnection(
  connectionString))
  {
  connection.Open();
  command.ExecuteNonQuery();
  }
 

应用程序角色和连接池
通过调用 sp_setapprole 系统存储过程激活了 SQL Server 应用程序角色之后,该连接的安全上下文无法重置。 但是,如果启用了池,连接将返回池,在重复使用池连接时会出错。 有关更多信息,请参见知识库文章“SQL application role errors with OLE DB resource pooling”(OLE DB 资源池出现 SQL 应用程序角色错误)。

应用程序角色替代项
如果您使用的是 SQL Server 2005,我们建议您利用可代替应用程序角色的新安全机制。 有关更多信息,请参见在 SQL Server 中创建应用程序角色 (ADO.NET)。

posted @ 2017-08-28 17:34  三人成虎  阅读(13202)  评论(0编辑  收藏  举报