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

|| 我有一个用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 externalConnection,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中以“没有自动故障转移(同步)的高安全性”模式将其标记为“同步主体”。 编辑5/26/11 我在SQL Server日志中看不到任何指示任何问题的信息。 (我无权访问该服务器上的Windows事件查看器,但我已要求某人来找我。)     
已邀请:
根据今天刚刚创建的MSDN Blog帖子(对于Google而言,万岁!):   Microsoft已经确认这是当前版本的ADO.NET中的问题。此问题将在Visual Studio 2011附带的ADO.NET版本中修复。      同时,我们要求使用以下解决方法:         将连接字符串超时增加到150秒。这将使第一次尝试有足够的时间进行连接(150 * .08 = 12秒)   在连接字符串中添加MinPool Size = 20。这将始终在池中至少维护20个连接,并且创建新连接的机会会减少,从而减少发生此错误的机会。   改善网络性能。将您的NIC驱动程序更新为最新的固件版本。当您的NIC卡与某些可伸缩网络包设置不兼容时,我们已经看到了网络延迟。如果您使用的是Windows Vista SP1或更高版本,则还可以考虑禁用“接收窗口自动调整”。如果已启用NIC分组,则禁用它是一个不错的选择。    这篇文章本身是一篇有趣的文章,涉及TCP / IP连接重试算法。对于所有说“嘿,看起来与镜像...有关的人”的人们,我感到很荣幸!并请注意有关此注释的注释是“由于来自SQL Server的响应速度慢或由于网络延迟”。 啊!!! 感谢所有张贴的人。现在,我们都必须要求对.NET Framework进行修补(或其他一些ADO.NET修补机制),因此我们不必等待(购买)Visual Studio 11。     
连接超时与命令超时不同。命令超时适用于已建立连接的情况,但是由于某些内部原因,服务器无法在要求的时间内返回任何结果。默认命令超时为30秒。 http://msdn.microsoft.com/zh-CN/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx 尝试在连接字符串中指定连接超时。默认值为15秒,这可能是您看到问题的原因。 您还可以在代码中指定连接超时: http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnection.connectiontimeout.aspx     
我偶尔会在我们拥有的旧数据库服务器上获得此信息(现在已有10年历史了)。当它确实发生时,是因为某事不断地用连接/查询来锤击该事。我的猜测是,您会发现在发生数据库服务器负载(或大量连接或类似情况)的情况下,以我的经验,如果可以优化代码,优化数据库,获得更强大的数据库服务器等都可以帮助您。 Piotr建议,您可以做的另一件事就是增加连接超时。不过,我仍然会优化一些东西(从长远来看应该会有所帮助)。     
我已经能够在某种程度上可靠地重现此问题。我有一项服务,当请求处理作业时,它将启动新的appdomain /线程中的处理。该线程将同时执行10到16个数据库查询。当我一个接一个地运行这些作业中的30个时,随机的一两个作业会因超时错误而崩溃。 我更改了连接字符串以使用Pooling = false关闭连接池,然后将错误更改为以下内容。由于连接是在Parallel.For内部发生的,因此会在聚合异常内抛出3或4次。
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 )
    
优化您在远程服务器上执行的查询将始终有帮助。为每个查询计时,并寻找长时间运行的查询。如果您只是在进行读取,则在SELECT语句上使用(NOLOCK)提示。这对我来说是个救生员。请仔细阅读以确保它适合您的应用程序。如果您有权访问远程数据库,请确保索引不会碎片化。这将导致查询执行的严重减慢。确保将索引重建/重组为SQL维护计划的一部分。在适当的地方添加新索引。 延长超时可能会使情况更糟。如果让查询运行更长的时间,则可能会有更多查询超时。超时是为了保护服务器和其他客户端访问它。将其稍微加重不是什么大不了的事,但是您不希望查询长时间运行会杀死服务器。     

要回复问题请先登录注册