2011-05-04 19 views
24

Tengo un servicio de Windows multiproceso que he desarrollado con VS 2010 (.NET 4.0) que puede tener desde unas pocas docenas de subprocesos, cada uno recuperando datos de un servidor lento a través de Internet y luego usando una base de datos local para registrar estos datos (por lo que el proceso está vinculado a Internet, no a la LAN ni a la CPU).Múltiples tiempos de espera simultáneos de conexión SQL en multiproceso de Windows Servicio

Con cierta regularidad, estoy consiguiendo una inundación/ráfaga/ráfaga del error de seguimiento de varios hilos simultáneamente:

System.Data.SqlClient.SqlException (0x80131904): Tiempo de espera agotado. El período de tiempo de espera transcurrido antes de la finalización de la operación o el servidor no responde.

La pila de llamadas para este error es típicamente:

en System.Data.ProviderBase.DbConnectionPool.GetConnection (DbConnection owningObject)

en System.Data.ProviderBase.DbConnectionFactory.GetConnection (DbConnection owningConnection)

en System.Data.ProviderBase.DbConnectionClosed.OpenConnection (DbConnection outerConnection, DbConnectionFactory ConnectionFactory)

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

no estoy especificando un tiempo de espera de conexión en la cadena de conexión, y hay otras aplicaciones y procesos de trabajo en esta base de datos. ¿Alguien ha encontrado este tipo de comportamiento y, de ser así, qué se hizo para evitarlo?

El método más comúnmente llamado en mi capa de acceso de datos se parece a esto, y todos mis otros métodos DAL seguir el mismo enfoque:

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(); 
} 

Gracias mucho!

EDITAR

Teniendo en cuenta los comentarios acerca de que esto ocurra en entornos de espejo, que debe mencionar que de hecho la base de datos en cuestión se refleja. Está marcado en SSMS como "Principal, Sincronizado", en el modo "Alta seguridad sin conmutación por error automática (síncrono)".

EDITAR 5/26/11

estoy viendo nada en los registros de SQL Server para indicar algún problema. (No tengo acceso al Visor de eventos de Windows en ese servidor, pero solicité que alguien me busque.)

+0

También estoy viendo exactamente el mismo problema, con la misma stacktrace. La base de datos a la que se conecta se duplica y la cadena de conexión especifica un asociado de conmutación por error. No he podido reproducir el mismo problema desde mi escritorio local, abriendo un montón de conexiones y, al no cerrarlas nunca, aparece un mensaje de excepción diferente. – BrandonAGr

+0

Estos enlaces informan sobre un problema similar, pero ninguno ofrece una solución: [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

+0

Creo que el problema no está en la conexión, cliente o base de datos. Pero en consultas ejecutadas. Verificarlos, p. reunir estadísticas de qué SP/consultas plantea una excepción más a menudo – abatishchev

Respuesta

14

De acuerdo con la MSDN Blog post hoy acaba de crear (hurra para Google!):

Microsoft ha confirmado que este es un problema en la versión actual de ADO.NET. Este problema se solucionará en la versión ADO.NET, se incluye con Visual Studio 2011.

Mientras tanto, hemos solicitar el uso de las soluciones siguientes:

  1. Aumentar el tiempo de espera de cadena de conexión a 150 seg. Esto le dará al primer intento suficiente tiempo para conectarse (150 * .08 = 12 segundos)

  2. Agregue el tamaño de MinPool = 20 en la cadena de conexión. Esto siempre mantendrá un mínimo de 20 conexiones en el conjunto y habrá menos posibilidades de crear una nueva conexión, reduciendo así la posibilidad de este error.

  3. Mejore el rendimiento de la red. Actualice sus controladores NIC a la última versión de firmware. Hemos visto la latencia de la red cuando su tarjeta NIC no es compatible con ciertas configuraciones de Scalable Networking Pack. Si tiene Windows Vista SP1 o superior, también puede considerar deshabilitar el ajuste automático de la ventana de recepción. Si tienes equipos NIC habilitados, deshabilitarlos sería una buena opción.

El mensaje en sí mismo es una lectura interesante, hablando de un algoritmo de reintento de conexión TCP/IP. Y felicitaciones a todas las personas que dijeron "¡Oye, parece que está relacionado con la duplicación ...!" Y tenga en cuenta que el comentario sobre esto es "debido a la respuesta lenta de SQL Server o debido a retrasos en la red".

UGH !!!

Gracias a todos los que publicaron. Ahora todos debemos pedir un parche para .NET Framework (o algún otro mecanismo de parches ADO.NET), así que no tenemos que esperar (y comprar) Visual Studio 11 ...

7

El tiempo de espera de la conexión es una cosa diferente que el tiempo de espera del comando. El tiempo de espera del comando se aplica a la situación cuando se establece una conexión, pero debido a algunas razones internas, el servidor no puede devolver ningún resultado dentro del tiempo requerido. El tiempo de espera predeterminado del comando es de 30 segundos. http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx

Intente especificar el tiempo de espera de conexión en la cadena de conexión. El valor predeterminado es 15 segundos, lo que puede ser el motivo del problema que ves. También puede especificar el tiempo de espera de conexión en el código: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectiontimeout.aspx

+0

Estoy pensando en aumentar el tiempo de espera de la conexión, pero este error * solo * se produce en las conexiones, no en la ejecución del procedimiento almacenado. El tiempo de espera del comando no tendrá nada que ver con esto. Pero mi preocupación es más acerca de por qué esto solo sucede de manera intermitente, y por qué afecta tantas conexiones intentadas al mismo tiempo. Tengo una persona encargada del desarrollo/DBA que dice que parece que algo está pasando con el grupo de conexiones del lado del servidor (y tengo que admitir que no sabía que existía un grupo de servidores * server *) Pero eso no ha sido verificado. – ALEXintlsos

+0

Si hay algo mal con el grupo de conexiones del servidor, habría algunas indicaciones de ello en el registro de errores del Servidor SQL. ¿Puedes verificar esto? Creo que si la red es más lenta a veces, las conexiones de todos los hilos sufrirían a causa de esto. Después de todo, cada conexión pasa por los mismos cables. Tuvimos un problema similar recientemente: tiempos de espera intermitentes experimentados por nuestro servidor de aplicaciones. Resultó que el enrutamiento entre servidores no era correcto y el rendimiento de la red fluctuaba mucho. Entonces nuestra aplicación arrojaría excepciones de tiempo de espera de todos los hilos. –

+0

Me temo que no hay nada en los registros de SQL Server. ¿Alguna recomendación sobre cómo detectar fluctuaciones en el rendimiento de la red? – ALEXintlsos

0

He podido reproducir este problema con cierta fiabilidad. Tengo un servicio que cuando se solicita un trabajo de procesamiento, se inicia el procesamiento en un nuevo appdomain/thread. Este hilo ejecutará de 10 a 16 consultas de bases de datos simultáneamente. Cuando ejecuto 30 de estos trabajos uno tras otro, uno o dos de los trabajos se bloquearán con el error de tiempo de espera excedido.

He cambiado la cadena de conexión para desactivar la agrupación de conexiones con Pooling = false y el error ha cambiado a lo siguiente. Esto se tira 3 o 4 veces dentro de una excepción agregado, ya que las conexiones están sucediendo dentro de un 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

me sale esto de vez en cuando en este servidor de base de datos antigua que hemos (llegando el 10 años de edad ahora). Cuando sucede, es porque algo está martillando esa cosa con conexiones/consultas constantemente. Supongo que encontrará que cuando suceda el servidor de la base de datos está bajo carga (o un gran número de conexiones o algo similar). De todos modos, en mi experiencia si puede optimizar el código, optimizar la base de datos, obtener una mayor servidor de base de datos, etc. todo ayuda. Otra cosa que puedes hacer, que Piotr sugiere, es simplemente el tiempo de espera para la conexión. Aún así, seguiría con la optimización de algunas cosas (debería ayudar a la larga).

0

Optimizar las consultas que está ejecutando en el servidor remoto siempre será de ayuda. Mida el tiempo de cada consulta y busque las de larga ejecución. Si solo hace lecturas, utilice la sugerencia (NOLOCK) en las instrucciones SELECT. Esto fue un salvavidas para mí. Simplemente lea para asegurarse de que sea apropiado en su aplicación. Si tiene acceso a la base de datos remota, asegúrese de indexes are not to fragmented. Esto causará una mayor desaceleración en la ejecución de consultas. Asegúrese de que los índices se reconstruyan/reorganicen como parte del plan de mantenimiento de SQL. Agregue nuevos índices donde sea apropiado.

Extender el tiempo de espera puede empeorar las cosas . Si permite que las consultas se ejecuten durante más tiempo, potencialmente, se agotarán las consultas. El tiempo de espera está allí para proteger el servidor y otros clientes que acceden a él. Saltar un poco no es un gran problema, pero no quiere que las consultas se ejecuten durante mucho tiempo matando al servidor.

+0

Creo que esta respuesta sería pertinente si tuviera el problema durante la ejecución del comando; sin embargo, está ocurriendo en la apertura de una conexión, por lo que las consultas aún no han comenzado. – ALEXintlsos

+0

"Si solo está haciendo lecturas, use la sugerencia (NOLOCK)": no es un buen consejo general a seguir. – StingyJack

+0

@StingyJack por eso existe la frase de advertencia "Solo lee para asegurarse de que sea apropiado en tu aplicación". en mi respuesta. – nbushnell

Cuestiones relacionadas