我正在与一位正在努力阻止以下错误的开发人员合作:
服务器将断开连接,因为客户端驱动程序在会话处于单用户模式时发送了多个请求。当会话中仍有批处理正在运行时,客户端发送重置连接的请求,或者当会话正在重置连接时客户端发送请求时,会发生此错误。请联系客户端驱动程序供应商。
发生此错误时,典型的结果是会话持有锁,但没有运行 SQL(sys.dm_exec_requests
session_id 没有行),并导致阻塞,直到它被杀死。阻塞的原因很简单,但如何阻止错误的发生却不是。
关于这个问题的一些事实:
- 客户端正在使用实体框架(是的,我知道...),启用了 MARS(是的,我知道...)
- SQL Server 版本为 10.00.5844 (SQL Server 2008 SP3 CU12)。他们可能不会在没有广泛测试的情况下升级主要版本,但应用更新的 CU 是可行的。
- 客户端程序显示
sys.dm_exec_connections
为 .Net SqlClient 数据提供程序 - 打开的连接似乎肯定启用了 MARS,如show
net_transport
所示。sys.dm_exec_connections
Session
- 根据Matt Neerincx在此线程中的评论,我被告知应用程序的连接字符串启用了异步处理(我自己无权访问应用程序服务器来确认这一点):
如果在连接字符串上设置 Async=true 应该可以防止这个问题。如果您使用 MARS 并在多个并发线程上使用相同的连接,则可能发生的情况是重置连接的调用可能会稍微延迟并触发此错误。如果您设置 Async=true,我们会在客户端驱动程序中执行额外的锁定以防止这种情况发生。
关于此错误的更多信息很少。它似乎表明客户端的程序sp_reset_connection
在批处理仍在运行时正在调用。我可以设置跟踪来确认这一点,但我必须记录很多不相关的活动,而且问题每隔几天才会发生一次。此外,我不确定开发人员是否能够利用这些证据来解决问题。
作为 DBA 或系统管理员,我是否可以使用任何其他技术来进一步解决此问题,或者我可以向开发人员建议任何可能为他提供有用信息或减少问题发生的可能性?
我没有看到它在任何地方说明正在使用哪个版本的 .NET Framework,但鉴于这个问题是在 2014 年 5 月提出的,并且 .NET Framework 版本 4.5 于 2012 年 8 月 15 日发布,以下内容关于/关键字的SqlConnection.ConnectionString的注释似乎相关:
Asynchronous Processing
Async
因此,找出正在使用的 Entity Framework 的确切版本以及 .NET Framework 的目标版本可能会有所帮助。
但是,听起来这个问题可能是连接池的结果。我怀疑连接池,因为在有关连接被关闭的错误消息之后,会话仍然存在。
首先要尝试的是通过将以下内容添加到连接字符串来简单地禁用连接池:
如果问题再也没有出现,那么这很可能是问题所在。我犹豫说这是问题所在,因为它并不完全是证据。它可能只是将频率从“每隔几天一次”减少到每隔几周甚至几个月一次。但是,如果这确实改善了一些事情,但应用程序经常访问服务器,并且您希望尽可能使用连接池,那么您可以尝试重新引入连接池,但在有限的意义上:您可以为
Connection Lifetime
关键词:如果连接超过 2 秒,这将在返回连接池时关闭连接。这允许进行一系列快速查询执行,而不需要每个都花费时间建立连接,同时不允许连接在那里逗留,可能持有锁等。
即使错误仍然发生,通过没有连接池来保持会话和连接处于活动状态,这也应该允许适当的清理、释放锁等。
只是为了说明这一点,因为它在问题的评论中受到质疑:实体框架使用多个活动结果集(MARS)进行延迟加载。因此,如果应用程序已被开发为使用延迟加载,那么关闭 MARS 就不是一种选择。