.net - maximo - sqlconnection timeout
Administrar la conectividad de la base de datos con ADO.NET (4)
Tenemos una aplicación que se basa en ADO.NET. Seguimos algunas mejores prácticas simples que nos permiten hacer uso del grupo de conexiones. Por ejemplo, un bloque de código que está utilizando una base de datos podría tener un aspecto similar a este:
using( DbConnection dbConnection = GetDatabaseConnection() ) { doWork(); }
FWIW, no hay nada especial acerca de GetDatabaseConnection. Establece una conexión con la base de datos que ejecuta MSSQL Server 2000. De hecho, se lee de la siguiente manera:
DbConnection GetDatabaseConnection() { return GetConnection(MyConnectionString); } DbConnection GetConnection(String connectionString) { try { SqlConnection dbConnection = new SqlConnection(connectionString); dbConnection.Open(); return dbConnection; } catch( InvalidOperationException ex ) { handleError(ex); throw; } catch( DbException ex ) { handleError(ex); } }
Como tal, nuestras conexiones se eliminan al final del alcance del bloque. Sin embargo, nos encontramos con un pequeño problema cuando comenzamos a probar la aplicación. Descubrimos que nuestra aplicación es muy explosiva, lo que significa que hay momentos en los que se vuelve muy hablador y luego se queda en silencio por un tiempo. El resultado es que podemos tener múltiples subprocesos simultáneamente para obtener una conexión.
Entonces imagina que tienes 10 hilos. Un lote de trabajo (por favor, no intente reformular el lote de trabajo) llega y se segmenta a través de algunos hilos. Cada subproceso luego intenta obtener una conexión y un boom, recibo una InvalidOperationException. He ajustado ConnectTimeout y todo lo que hace es alargar el tiempo hasta que recibo una ráfaga de excepciones. Una vez que supero la fase de "conclusión", la aplicación está bien. Luego se quita de nuevo, las conexiones "desaparecen" y el proceso comienza de nuevo.
También intenté ajustar LoadBalanceTimeout pero las excepciones continúan llegando. ¿Alguno de ustedes ha visto este problema antes? Cualquier pensamiento ... Lanzaré un par de los míos.
- Continuamente mantener una conexión "caliente"
- Intenta abrir nuevamente la conexión hasta un # de intentos
- Implementar mi propia agrupación de conexiones (bleah, no estoy interesado en reinventar la rueda)
Editar:
La mayoría de los foros que he leído han desalentado el aumento del tamaño del grupo de conexiones. Por defecto, el grupo de conexiones tiene un límite superior de 50 conexiones (eso es más que suficiente, si tengo que aumentarlo, algo está fundamentalmente mal en otro lugar). Lo que noto es que cuando ConnectTimeout está bajo, se produce InvalidOperationException. Es como si el giro de la conexión fuera demasiado largo y las conexiones pendientes agotaran su tiempo de espera.
MARS es ciertamente una opción ... El texto de InvalidOperationException.Message es:
Tiempo agotado. El tiempo de espera transcurrido antes de obtener una conexión del grupo. Esto puede haber ocurrido porque todas las conexiones agrupadas estaban en uso y se alcanzó el tamaño máximo de la agrupación.
Pregunta 1: ¿su método GetDatabaseConnection () deriva un nuevo hilo para generar la conexión de la base de datos y devolverlo al hilo principal ... o hay varios hilos que intentan acceder a este aspecto del método ... o es este un método método compartido / estático que solo toma una conexión del grupo?
Pregunta 2: ¿Qué marca y modelo es su servidor de base de datos? ¿Servidor SQL? ¿Oráculo? PostgreSQL?
Pregunta 3: ¿Necesita todo el trabajo realizado en diferentes conexiones, o si todo se puede hacer en una, sería suficiente? Si SQL Server, entonces quizás MARS permita múltiples conjuntos de registros en una sola conexión podría ayudar, pero puede no ser factible para su aplicación.
Pregunta 4: ¿Cuál es el detalle en la excepción devuelta?
Intentando obtener una idea clara de cómo está funcionando la arquitectura de su aplicación ...
(PD: ¿Alguien sabe cómo marcó una "respuesta" como "no una respuesta, sino una solicitud de mayor aclaración" ... es decir, para esta "respuesta")
Desde MSDN ( http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx ):
Cuando se solicita un objeto SqlConnection, se obtiene del grupo si hay una conexión utilizable disponible. Para ser utilizable, una conexión debe estar sin usar, tener un contexto de transacción coincidente o no asociarse con ningún contexto de transacción , y tener un enlace válido al servidor.
El conjunto de conexiones satisface las solicitudes de conexiones al reasignar las conexiones a medida que se vuelven a liberar en el grupo. Si se ha alcanzado el tamaño máximo de la agrupación y no hay conexión utilizable disponible, la solicitud se pone en cola. El recolector intenta recuperar las conexiones hasta que se alcanza el tiempo de espera (el valor predeterminado es 15 segundos). Si el agrupador no puede satisfacer la solicitud antes de que expire el tiempo de espera de la conexión, se genera una excepción .
Traducción: compruebe sus contextos de transacción ... si tiene un tamaño de grupo de 10 conexiones y se han creado 10 conexiones en diferentes transacciones, está equivocado.
Tenga en cuenta que una conexión cortada solo se puede detectar después de intentar comunicarse con el servidor . Si se encuentra una conexión que ya no está conectada al servidor, se marca como no válida. Las conexiones no válidas se eliminan del grupo de conexiones solo cuando se cierran o recuperan.
Si existe una conexión con un servidor que ha desaparecido, esta conexión puede extraerse del grupo incluso si el grupo de conexión no ha detectado la conexión cortada y la ha marcado como no válida. Este es el caso porque la sobrecarga de verificar que la conexión sigue siendo válida eliminaría los beneficios de tener un colector haciendo que se produzca otro viaje de ida y vuelta al servidor. Cuando esto ocurre, el primer intento de utilizar la conexión detectará que la conexión se ha cortado y se lanzará una excepción .
Traducción: ¿Realmente no puedes confiar en que una conexión esté conectada? El artículo realmente no explica cómo manejar esto ...
Podrías intentar borrar manualmente el grupo ocasionalmente usando ClearAllPools y ClearPool, pero esto todavía me parece una curita, me da escalofríos.
El artículo también analiza los contextos de seguridad, diciendo:
Después de que se haya activado una función de aplicación SQL Server llamando al procedimiento almacenado del sistema sp_setapprole, el contexto de seguridad de esa conexión no se puede restablecer. Sin embargo, si la agrupación está habilitada, la conexión se devuelve al grupo y se produce un error cuando se reutiliza la conexión agrupada.
Estoy comenzando a preguntarme por qué uso la agrupación de conexiones ...
Y finalmente:
Fragmentación de la piscina debido a la seguridad integrada
Las conexiones se agrupan de acuerdo con la cadena de conexión más la identidad del usuario. Por lo tanto, si utiliza la autenticación básica o la autenticación de Windows en el sitio web y un inicio de sesión de seguridad integrado, obtendrá un grupo por usuario. Aunque esto mejora el rendimiento de las solicitudes de base de datos posteriores para un solo usuario, ese usuario no puede aprovechar las conexiones realizadas por otros usuarios. También da como resultado al menos una conexión por usuario al servidor de la base de datos.
Por lo tanto, si usa seguridad integrada en una aplicación web, puede llenar su grupo de conexiones si tiene suficientes usuarios.
Sin conocer más detalles sobre su aplicación, es difícil acercarse a lo que podría estar desconcertando, pero espero que esto le brinde algunas ideas sobre dónde buscar.
HTH
Puede intentar configurar "Max Pool Size" más alto. También es posible que desee intentar explícitamente llamar "Cerrar" en la conexión.
Según MSDN, InvoidOperationException es lanzado por SqlConnection.Open si no ha especificado un origen de datos o servidor, o si la conexión ya está abierta.
¿Estás seguro de que no tienes llamadas a SqlConnection. Abre en tu método "doWork"?
Además, su código en el método GetConnection absorbe DbException.