2011-05-04 210 views
24

我有一个多线程的Windows服务,我用VS 2010(.NET 4.0)从一个缓慢的服务器开发了可从几随时随地有几十个线程,每个线程检索数据通过互联网,然后使用本地数据库记录此数据(因此该过程是Internet连接的,而不是LAN或CPU绑定的)。多个同时SQL连接超时在多线程Windows服务

有一定的规律性,我得到一个洪水/乱舞/同时从多个线程爆了以下错误:

System.Data.SqlClient.SqlException(0x80131904):超时过期。操作完成之前超时的时间或服务器没有响应。

此错误的调​​用堆栈通常是:

在System.Data.ProviderBase.DbConnectionPool.GetConnection(的DbConnection owningObject)

在System.Data.ProviderBase.DbConnectionFactory.GetConnection(的DbConnection owningConnection)

在System.Data.ProviderBase.DbConnectionClosed.OpenConnection(的DbConnection outerConnection,DbConnectionFactory connectionFactory的)

在System.Data.SqlClient.SqlConnection.Open()

我不是指定连接字符串中连接超时,还有其他的应用程序和进程在该数据库的工作。有没有人遇到过这种行为,如果有的话,做了什么来阻止它?

最常调用的方法在我的数据访问层看起来是这样的,所有我的其他DAL方法遵循相同的方法:

using (SqlConnection con = new SqlConnection(GetConnectionString())) 
using (SqlCommand cmd = new SqlCommand("AddGdsMonitorLogEntry", con)) 
{ 
    cmd.CommandType = CommandType.StoredProcedure; 

    /* setting cmd.Parameters [snipped] */ 

    // We have been getting some timeouts writing to the log; wait a little longer than the default. 
    cmd.CommandTimeout *= 4; 

    con.Open(); 

    cmd.ExecuteNonQuery(); 
} 

非常感谢!

编辑

鉴于有关此方面的镜像环境中发生的意见,我的确应该提到的是有问题的数据库镜像。它在SSMS中标记为“Principal,Synchronized”,在“没有自动故障转移(同步)的高安全性”模式中。

编辑11年5月26日

我看到什么在SQL Server日志来说明任何问题。 (我没有访问Windows事件查看器的服务器上,但我问的人找我。)

+0

我也看到完全相同的问题,使用相同的堆栈跟踪。它连接的数据库是镜像的,连接字符串指定了故障转移伙伴。我一直无法从本地桌面重现相同的问题,打开一堆连接并从不关闭它们会产生不同的异常消息。 – BrandonAGr 2011-05-13 20:05:31

+0

这些链接报告类似的问题,但没有提供解决方案:[1](http://stackoverflow.com/questions/3140738/why-timeout-may-occur-in-sqlconnection-open)[2](http: //blog.brianhartsock.com/2009/09/29/interesting-sql-server-mirroring-problem/)[3](http://social.msdn.microsoft.com/Forums/en/sqldatabasemirroring/thread/918e4a7f -1fc5-4679-958f-4c4f07b6ae76)[4](http://social.msdn.microsoft.com/Forums/en/adodotnetdataproviders/thread/e93fae99-a832-407f-9e80-f7a27b1c6194)[5](http:/ /social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/d3798fe7-fc7f-45aa-87ca-cd365abc4b55) – BrandonAGr 2011-05-13 20:11:36

+0

我认为问题不在于连接,客户端或数据库。但在查询执行。验证它们,例如收集统计信息SP /查询更频繁地引发异常 – abatishchev 2011-05-15 14:11:45

回答

14

根据MSDN Blog post刚刚创建的今天,以(万岁谷歌!):

Microsoft已经确认这是在ADO.NET的当前版本中的一个问题。这个问题将在ADO.NET版本,船舶与Visual Studio 2011年

在此期间,我们要求使用以下解决方法:

  1. 增加连接字符串超时150秒。这将给第一次尝试足够的时间连接(150 * .08 = 12秒)

  2. 在连接字符串中添加MinPool Size = 20。这将始终保持池中至少20个连接,并且创建新连接的机会将减少,从而减少出现此错误的几率。

  3. 提高网络性能。将您的网卡驱动程序更新到最新的固件版本。当您的NIC卡与某些Scalable Networking Pack设置不兼容时,我们已经看到网络延迟。如果您使用的是Windows Vista SP1或更高版本,则可能会考虑禁用接收窗口自动调整功能。如果您启用了网卡绑定,禁用它将是一个不错的选择。

的职位本身是一个有趣的阅读,谈论的是TCP/IP连接重试算法。并赞扬所有的人谁说:“嘿,这看起来像它与镜像......”!并注意关于这个问题的评论:“由于SQL Server响应缓慢或网络延迟”。

UGH !!!

感谢所有发布的人。现在我们都必须向.NET Framework(或其他ADO.NET修补机制)寻求补丁,因此我们不必等待(并购买)Visual Studio 11 ...

7

连接超时比命令超时不同的事情。命令超时适用于建立连接时的情况,但由于某些内部原因,服务器无法在所需时间内返回任何结果。默认命令超时是30秒。 http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx

尝试指定连接字符串中的连接超时。默认值是15秒,这可能是您看到问题的原因。 您还可以指定代码中的连接超时: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectiontimeout.aspx

+0

我想增加连接超时,但是这个错误是*只*发生在连接上,而不是存储过程执行。命令超时与此无关。但是我的担心更多的是为什么这种情况只是间歇性地发生,为什么它会同时影响这么多尝试的连接。我在这里有一个DBA /开发人员,他说这听起来像是服务器端连接池中可能会有某些事情发生(我不得不承认我不知道有* server *端池这样的东西)。但是这没有得到证实。 – ALEXintlsos 2011-05-24 13:28:50

+0

如果服务器连接池出现问题,那么在SQL Server错误日志中会有一些指示。你能证实这一点吗? 我认为,如果网络速度较慢,所有线程的连接都会因此而受到影响。所有的连接都通过相同的电线。 我们最近有类似的问题 - 我们的应用服务器经历了间歇性超时。事实证明,服务器之间的路由不正确,网络性能波动很大。然后我们的应用程序会抛出所有线程的超时异常。 – 2011-05-24 23:01:25

+0

恐怕SQL Server日志中没有任何东西。有关如何检测网络性能波动的任何建议? – ALEXintlsos 2011-05-26 14:11:07

0

我已经能够稍微可靠地重现此问题。我有一个服务,当处理作业被请求时,它开始处理一个新的appdomain /线程。该线程将同时执行10到16个数据库查询。当我一个接一个地运行这些作业中的30个时,随机的一个或两个作业会因超时错误而崩溃。

我更改了连接字符串以关闭Pooling = Pooling = false,然后错误更改为以下内容。这被抛出3或4次合计异常中,由于连接内的Parallel.For

System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() 
    at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) 
    at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket() 
    at System.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(Boolean encrypt, Boolean trustServerCert, Boolean& marsCapable) 
    at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity) 
    at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, SqlConnection owningObject) 
    at System.Data.SqlClient.SqlInternalConnectionTds.LoginWithFailover(Boolean useFailoverHost, ServerInfo primaryServerInfo, String failoverHost, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout) 
    at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance) 
    at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance) 
    at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection) 
    at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup) 
    at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) 
    at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 
    at System.Data.SqlClient.SqlConnection.Open() 
    at Tps.PowerTools.CoreEngine.V5.DataAccess.DataContext.ExecuteQuery(PtQuery query, ValueStore`1 store, String readerDescription) in C:\SourceCode\Tps.PowerToolsV1\Trunk\Libraries\CoreEngine\CoreEngine.V5\DataAccess\DataContext.cs:line 326 
    at Tps.PowerTools.CoreEngine.V5.DataAccess.DataContext.<StockHistoricalData>b__15(PtQuery query) in C:\SourceCode\Tps.PowerToolsV1\Trunk\Libraries\CoreEngine\CoreEngine.V5\DataAccess\DataContext.cs:line 302 
    at System.Threading.Tasks.Parallel.<>c__DisplayClass32`2.<PartitionerForEachWorker>b__30() 
    at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) 
    at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object) 
1

我得到这个每一次在这个古老的数据库服务器上的,而我们(10上来发生现在岁)。当它发生的时候,虽然这是因为有些东西在不断地用连接/查询来锤击这件事。我的猜测是,你会发现当数据库服务器发生负载时(或者大量的连接或者这些线上的某些东西)无论如何,根据我的经验,如果你可以优化代码,优化数据库,变得更加强大数据库服务器等都有所帮助。 Piotr建议你可以做的另一件事是简单地延长连接的超时时间。我仍然会通过并优化一些东西,虽然(应该从长远来看有所帮助)。

0

优化您在远程服务器上执行的查询将始终有帮助。为每个查询计时并查找长时间运行的查询。如果您只是在读取数据,请在SELECT语句中使用(NOLOCK)提示。这对我来说是一种拯救生命。只需阅读它,以确保它适用于您的应用程序。如果您有权访问远程数据库,请确保indexes are not to fragmented。这会导致查询执行速度下降。确保索引被重建/重组为SQL维护计划的一部分。在适当的地方添加新索引。

延长超时可能会使变得更糟。如果让查询运行时间更长,则可能会有更多查询超时。超时是为了保护服务器和其他客户端访问它。将其稍微提升一点并不是什么大问题,但是您不希望查询长时间运行而终止服务器。

+0

我认为如果我在执行命令期间遇到问题,这个答案是恰当的;然而,它发生在连接开放时,所以查询甚至还没有开始。 – ALEXintlsos 2011-05-24 13:30:05

+0

“如果你只是在读取,然后使用(NOLOCK)提示” - 这不是一般的忠告。 – StingyJack 2016-11-02 13:27:06

+0

@StingyJack这就是为什么有这样的告诫句“只需阅读它,以确保它在您的应用程序中是适当的。”在我的回应中。 – nbushnell 2016-11-14 19:53:30