多线程Windows服务中的多个同时SQL连接超时

时间:2011-05-04 14:20:40

标签: sql-server multithreading connection-timeout

我有一个使用VS 2010(.NET 4.0)开发的多线程Windows服务,它可以有几个到几十个线程,每个线程通过Internet从慢速服务器检索数据,然后使用本地数据库记录此数据(因此进程受Internet限制,而不是LAN或CPU绑定)。

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

  

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”,“高安全性,无自动故障转移(同步)”模式。

编辑5/26/11

我在SQL Server日志中看不到任何问题。 (我无法访问该服务器上的Windows事件查看器,但我已经要求有人找我。)

5 个答案:

答案 0 :(得分:15)

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

  

Microsoft已确认这是当前版本的ADO.NET中的一个问题。此问题将在ADO.NET版本中修复,随Visual Studio 2011一起提供。

     

与此同时,我们要求使用以下变通方法:

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

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

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

  6.   

帖子本身是一个有趣的读物,谈论TCP / IP连接重试算法。并且对所有说“嘿,这看起来与镜像有关......”的人们感到荣幸!请注意有关此问题的评论“因为SQL Server响应缓慢或网络延迟”。

UGH !!!

感谢所有发帖的人。现在我们都必须要求.NET Framework(或其他一些ADO.NET补丁机制)的补丁,所以我们不必等待(并购买)Visual Studio 11 ......

答案 1 :(得分: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

答案 2 :(得分:1)

我在这个旧的数据库服务器上偶尔得到这个(现在已经10岁了)。当它确实发生的时候,因为有些东西正在不断地用连接/查询来锤击那个东西。我的猜测是你会发现,当它发生时,数据库服务器处于负载状态(或大量连接或沿着这些线路的东西)无论如何,根据我的经验,如果你可以优化代码,优化数据库,变得更加强大数据库服务器等都有帮助。 Piotr建议你可以做的另一件事就是连接超时。我仍然会经历并优化一些东西(从长远来看应该有所帮助)。

答案 3 :(得分:0)

我能够在某种程度上可靠地重现这个问题。我有一项服务,当请求处理作业时,它启动新的appdomain /线程中的处理。该线程将同时执行10到16个数据库查询。当我一个接一个地运行30个这样的作业时,随机的一个或两个作业将因超时错误而崩溃。

我更改了连接字符串以关闭连接池,使用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 )

答案 4 :(得分:0)

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

延长超时可能会使事情更糟。如果您让查询运行时间更长,则可能会有更多查询超时。超时用于保护服务器和访问它的其他客户端。把它搞砸了并不是什么大不了的事,但是你不想让查询长时间运行来杀死服务器。