分享

ASP.NET与数据库连接池

 悟静 2012-06-14
99人阅读 评论(0) 收藏 举报

防止可淹没应用程序的池溢出

大多数 ADO.NET 数据提供程序使用连接池,以提高围绕 Microsoft 断开连接的 .NET 结构构建的应用程序的性能。应用程序首先打开一个连接(或从连接池获得一个连接句柄),接着运行一个或多个查询,然后处理行集,最后将连接释放回连接池。如果没有连接池,这些应用程序将花费许多额外时间来打开和关闭连接。

当您使用 ADO.NET 连接池来管理基于 Web 的应用程序和客户端/服务器 Web 服务应用程序的连接时,您的客户通常会获得更快的连接和更好的总体性能。但是,当您的应用程序或 Web 站点上突然涌入了同时希望进行连接的大量客户时,会发生什么事情呢?您的应用程序会沉没,还是会游泳?就像救生员一样,您需要仔细监视连接池,以维护它的良好性能,并防止连接池发生溢出。我们首先探讨连接池可能溢出的原因,然后讨论如何编写代码或使用 Windows 性能监视器来监视连接池。

正如我于 2003 5 月发表的 Swimming in the .NET Connection Pool (InstantDoc ID 38356) 一文中讨论的那样,当您使用连接池时,您需要知道许多有关可伸缩性和性能的详细信息。请记住,您需要监视和管理两个基本因素:每个池管理的连接数和连接池的数量。在一个有效的生产系统中,池的数量通常很少(1 10),而且,使用中的连接的总数也很少(少于 12 )有效的查询只用不到一秒钟的时间就可以完成,并断开连接。因此,即使有数百个客户同时访问您的 Web 站点,相对较少的几个连接常常足以处理整个负载。为了使您的应用程序有效地运行,您必须使连接资源处于自己的控制之下,并要监视池的状态,这样,在监视池发生溢出以及您的客户开始抱怨(或离开您的网站)之前您会收到某种警告。

为什么会发生连接池溢出?

参加电子邮件讨论组的人常常抱怨应用程序是如何在测试中是而在形成为产品时就变成了的。有时,他们会报告说,当连接了大约 100 个客户端时,应用程序会停止或挂起。请记住,一个池中的默认连接数是 100。如果您尝试从池中打开 100 个以上的连接,ADO.NET 会使应用程序的连接请求排队等候,直到有空闲的连接。应用程序(及其用户)将这种情况视为进入 Web 页的延迟或视为应用程序死锁。让我们首先讨论一下这个问题是如何产生的。

ADO.NET 中,SqlClient .NET 数据提供程序为您提供了两种打开和管理连接的方法。首先,当您需要手工管理连接时,可以使用 DataReader 对象。利用这种方法,您的代码将构造一个 SqlConnection 对象,设置 ConnectionString 属性,然后使用 Open 方法来打开连接。当代码完成 DataReader 后,您要在 SqlConnection 对象停止作用之前关闭 SqlConnection。要处理行集,您可以将 DataReader 传递到应用程序中的另一个例程,但仍然需要确保 DataReader 及其连接处于关闭状态。如果您不关闭 SqlConnection,代码会泄漏每个操作的连接,于是连接池对连接进行累积,最后便发生溢出。与 ADO Visual Basic (VB) 6.0 中的情况不同,.NET ***回收器不会为您关闭 SqlConnection 并进行清理。我稍后要讨论的 清单 1 显示了如何打开连接和生成 DataReader 以从一个简单的查询返回行集,来向连接池施加压力的。

您也可能在使用 DataAdapter 对象时遇到问题。DataAdapter Fill Update 方法可自动打开

 

 

用不到五个连接来处理每天的几十万次点击。

标注 A 中的例程创建 SqlConnection 对象和 SqlCommand 对象,设置 CommandText,并打开连接。然后,标注 B 中的代码确定执行 DataReader 时是否使用 CommandBehavior.CloseConnection,这取决于用户在 Web 窗体上选择了哪些 CheckBox 控件。

在标注 C 的代码中,我指定是否将 DataReader 行集绑定到 DataGrid,或者是否在整个行集中进行循环。标注 C 的代码测试当您到达通过 DataReader 从数据提供程序传递回来的行集的末尾时会发生什么事情。

现在,我使用标注 D 中的代码来指定是手工关闭连接还是让某个其他操作(例如,数据绑定)来完成这项工作。坦白地说,以手工方式关闭连接通常是最安全的,因此,您可以肯定连接不会被孤立。

如果代码成功地运行到这一步,说明我已经成功地打开和关闭了 110 个连接。不过,如果出了问题,标注 E 的代码中的异常处理程序会将异常(通常是 Timeout)作为 InvalidOperationException 捕获,该异常是连接池已满时 ADO.NET 的响应方式。

1 汇总了各个选项使例程成功运行或失败的方式。请注意,如果您不设置 CommandBehavior.CloseConnection 选项,您的操作最终会失败即使在使用绑定控件的情况下也是如此。即使您使用该选项,但如果您没有使用复杂的绑定控件,或者没有手工关闭 SqlDataAdapter SqlConnection,该进程仍然会失败。

当我结束了这些示例应用程序的运行后,我已经生成了 1000 多个以上的池连接所有连接均处于孤立状态。虽然“SQL Server 用户连接计数为 0,但留下大约 40 个连接池。在我重新引导系统之前,孤立的池不会消失。

我用于此测试的示例应用程序包括使用 DataAdapter 来返回行的例程。除非您手工管理连接,否则,DataAdapter 将正确地打开和关闭 SqlConnection 对象,因此,您不太可能遇到孤立的池连接。不过,如果您的应用程序同时使用 DataReader DataAdapter,您可能会发现,如果某个连接与一个未关闭的 DataReader 相关联,则 DataAdapter 无法针对该连接运行查询。

确定连接池何时达到最大连接数

正如我在 Swimming in the .NET Connection Pool 一文中讨论的那样,当连接池达到您通过 Max Pool Size ConnectionString 选项指定的最大连接数时,ADO.NET 将阻止任何随后打开额外连接的尝试。如果某个连接在您在 ConnectionTimeout 选项中指定的时间之前变为可用,.NET 数据提供程序将向您的应用程序传递一个指向该连接的指针,以便将控件返回给应用程序。不过,如果没有及时释放任何连接,连接请求将引发 InvalidOperationException 异常。

现在您必须决定要采取的措施,我不建议您告诉用户您已经用完了所有连接。有些应用程序会通知用户系统正忙于帮助其他客户,并建议用户稍后进行访问。其他应用程序则播放一段动画,通知用户系统尚未死锁,而是正在忙于处理他们的请求。同时,您的代码重新尝试操作。在所有情况下,您应该

记录这些故障,以便帮助诊断问题的症结所在,并记录您已经耗尽了资源。

监视连接池

您已经打开和关闭了一个连接,现在您希望知道该连接是否仍然处于打开状态。您可以使用几种方法来确定有多少连接仍然处于打开状态,以及它们正在执行何种操作:

 

运行 sp_who sp_who2。这些系统存储过程从 sysprocess 系统表返回信息,该系统表显示所有工作进程的状态及其有关信息。通常,您会看到每个连接有一个服务器进程 ID (SPID)。如果您是通过在连接字符串中使用 Application Name 参数来命名您的连接的,那么,您将很容易找到工作的连接。

使用带有 SQLProfiler TSQL_Replay 模板的 SQL Server 事件探查器来跟踪打开的连接。如果您很熟悉事件探查器,此方法比通过使用 sp_who 进行轮询要更容易。

 

使用性能监视器来监视池和连接。我稍后再讨论此方法。

在代码中监视性能计数器。您可以通过使用例程来提取计数器或通过使用新的 .NET PerformanceCounter 控件来监视连接池的状况和已建立的连接的数量。这两种方法都包括在您可以从 http://www. 进行下载的示例应用程序中。

现在我们将讨论如何查找连接池计数器,以及如何使用这些监视方法。

连接池计数器在哪里?要监视连接池计数器,您必须监视 ADO.NET 在其中创建和增加这些计数器的系统。如果您从远程系统进行连接,ADO.NET 并不总是在 Microsoft IIS 服务器或 SQL Server 上创建池;它在 ADO.NET 代码运行的系统上创建池。此系统可以是运行 IISWeb 应用程序或 Web 服务的远程 Windows 或中间层系统。相反,SQL Server 性能计数器位于 SQL Server 系统上而不是客户端上。

使用性能监视器来监视池。如果您使用 Microsoft 管理控制台 (MMC) Windows 2000 系统监视器管理单元,则您可以通过从 Performance 对象下拉列表中选择 .NET CLR Data 来用图形表示 SqlClient 计数器,如 1所示。请注意,您可以通过选择 _global_ 计数器实例来监视所有进程,或者,您可以查看某个特定实例每个池生成自己的一组监视器。性能监视器可列出这些计数器,并将它们作为所选定的性能对象的实例提供。但性能监视器不会公开这些计数器,除非有实例需要它们进行监视。例如,图 1 显示了 .NET CLR Data 性能对象,但没有列出特定实例。这意味着您必须至少创建一个连接,以便使 _global_ 实例连同每个进程的特定实例一起出现。这种行为对于您的代码来说是个问题;您将无法使用 PerformanceCounter 控件来返回其中的任何计数器,直到 ADO.NET 在打开连接时创建这些计数器。所以说,这个规定真有点令人左右为难。当您使用此方法时,因为缺少有效计数器实例,所以会引发异常此时要准备好捕获异常。

您还可以通过使用 SQL Server 性能计数器 User Connections 来监视打开的连接的数量。该计数器被列在 Performance 对象下拉列表中的 SQL Server: General Statistics 下。我喜欢监视 User Connections 值和一些所选定的 .NET CLR Data SqlClient 计数器(我稍后将讨论此内容),因为我可以获得我需要的信息,而不必担心实例。

使用代码来监视性能计数器。当您需要以编程方式监视连接池时,您可以编写代码来监视由 SqlClient 管理的性能计数器这些计数器与 MMC Windows NT 性能监视器管理单元所提供的计数器是相同的。编写执行监视的代码似乎是一件有些令人畏惧的事情。但我已经提供了从 SqlClient 提供程序的内部工作提取这些计数器的例程的快照(作为本文提供的可下载程序之一)。

您可以编写检查 2显示的五个计数器的代码。通过利用这五个计数器,您可以实时监视连接池。.NET 预期您会在性能监视器中提供一个类别复制的 Performance Object并从那些注册到系统的计数器中选择适当的计数器。要访问 SqlClient 计数器,请将该类别设置为 .NET CLR Data

使用 PerformanceCounter 控件。您可能会发现,在设计时向您的应用程序窗体添加 PerformanceCounter 要比手工编写代码来访问性能计数器更加容易。要使用 PerformanceCounter 控件,请从“Visual Studio .NET 工具箱组件菜单中选择一个 PerformanceCounter,将它拖到您的应用程序窗体,然后设置属性,如 2 所示。这些控件工作在 Web 窗体和 WinForms 应用程序中。

因为 PerformanceCounter 控件提供了方便的下拉列表,所以,您可以在设计时看到任何一种性能计数器类别、计数器名称和特定实例您将要运行的实例除外。这意味着您必须使用图 2 显示的方法来捕获应用程序正在使用的池的适当实例。为了回避这个问题,我选择 _global_ 实例。再次说明一下,此方法假设某个应用程序已经至少创建了一个池,因此您需要做好不存在计数器实例时 ADO.NET 引发异常的准备,就像它在不存在池连接时也会引发异常一样。

注意不准确的池计数。因为 SqlClient .NET 数据提供程序中存在 .NET 框架 1.1 尚未解决的错误,所以,性能计数器会在池实际上已经删除时错误地指示池仍然存在。我能通过结束 MMC 性能监视器管理单元、然后结束 Visual Studio .NET 来验证池已经不再存在。这些步骤说明,.NET 数据提供程序在创建连接池的进程结束时会正确地删除连接池。显然,这种不准确性降低了性能计数器在监视池方面的有效性,所以我希望 Microsoft 将来能解决这个问题。

计数器不显示的内容

您可能会面临的一个问题是无法从计数器或 SqlClient 属性看到每个池的配置。每个 SqlConnection 对象的 ConnectionString 保存着这些池设置的密钥。因为您不能依赖于默认设置,所以很难确定池几乎已满或很难使用。这会成为未来版本的 ADO.NET 的另一个方便功能。

不过,假设您知道各个连接池 ConnectionString 参数的值,则利用清单 1 中的代码,您可以很容易地设置一个计时器来检查您创建的特定池并报告使用百分比。然后,监视应用程序会向您发出警报,以便您可以解决问题并防止溢出。

最后,请记住,ADO.NET 采用的方法与基于 COM ADO 有所不同。Visual Basic .NET 完全改变了放弃对象的方式,并且不再确保 Connection 对象在停止作用时被关闭。请确保 SqlConnection 对象(或任何 Connection 对象)在停止作用之前被关闭。

连接池是一种非常强大的功能,它可以提高应用程序的性能。但如果您不是一个出色的救生员,您的连接池会成为一个危害而不是一个优点。我希望本文讨论的方法有助于您有效地监视连接池并满足用户的需要。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多