¿Cómo puedo resolver un problema de grupo de conexiones entre ASP.NET y SQL Server?

Los últimos días vemos demasiado este mensaje de error en nuestro sitio web:

“Excedió el tiempo de espera. 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”.

No hemos cambiado nada en nuestro código por un tiempo. Revisé el código para verificar las conexiones abiertas que no se cerraron, pero encontré que todo estaba bien.

  • ¿Como puedo resolver esto?

  • ¿Necesito editar este grupo?

  • ¿Cómo puedo editar el número máximo de conexiones de este grupo?

  • ¿Cuál es el valor recomendado para un sitio web de alto tráfico?


Actualizar:

¿Debo editar algo en IIS?

Actualizar:

Descubrí que el número de conexiones activas está entre 15 y 31, y encontré que el número máximo permitido de conexiones configuradas en el servidor SQL es de más de 3200 conexiones, es 31 demasiado o debería editar algo en la configuración de ASP.NET ?

En la mayoría de los casos, los problemas de agrupación de conexiones están relacionados con “fugas de conexión”. Es probable que su aplicación no cierre sus conexiones a la base de datos de manera correcta y consistente. Cuando deja conexiones abiertas, permanecen bloqueadas hasta que el recolector de elementos no utilizados .NET las cierra por usted llamando a su método Finalize() .

Desea asegurarse de que realmente está cerrando la conexión . Por ejemplo, el siguiente código provocará una pérdida de conexión, si el código entre .Open y Close arroja una excepción:

 var connection = new SqlConnection(connectionString); connection.Open(); // some code connection.Close(); 

La forma correcta sería esta:

 var connection = new SqlConnection(ConnectionString); try { connection.Open(); someCall (connection); } finally { connection.Close(); } 

o

 using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); someCall(connection); } 

Cuando su función devuelve una conexión de un método de clase, asegúrese de almacenarla en caché localmente y llamar a su método Close . Perderá una conexión con este código, por ejemplo:

 var command = new OleDbCommand(someUpdateQuery, getConnection()); result = command.ExecuteNonQuery(); connection().Close(); 

La conexión devuelta desde la primera llamada a getConnection() no se cierra. En lugar de cerrar su conexión, esta línea crea una nueva e intenta cerrarla.

Si usa SqlDataReader o OleDbDataReader , ciérrelos. Aunque cerrar la conexión en sí parece ser el truco, dedique un esfuerzo extra a cerrar los objetos de su lector de datos explícitamente cuando los utilice.


Este artículo ” ¿Por qué se desborda un pool de conexiones? ” De MSDN / SQL Magazine explica muchos detalles y sugiere algunas estrategias de depuración:

  • Ejecute sp_who o sp_who2 . Estos procedimientos almacenados del sistema devuelven información de la tabla del sistema sysprocesses que muestra el estado y la información sobre todos los procesos en funcionamiento. En general, verá un ID de proceso del servidor (SPID) por conexión. Si nombró su conexión utilizando el argumento Nombre de la aplicación en la cadena de conexión, sus conexiones de trabajo serán fáciles de encontrar.
  • Use el Analizador de SQL Server con la plantilla TSQL_Replay de TSQL_Replay para rastrear las conexiones abiertas. Si está familiarizado con Profiler, este método es más fácil que el sondeo utilizando sp_who.
  • Use el Monitor de rendimiento para monitorear las piscinas y las conexiones. Discuto este método en un momento.
  • Controle los contadores de rendimiento en el código. Puede supervisar el estado de su grupo de conexiones y la cantidad de conexiones establecidas mediante el uso de rutinas para extraer los contadores o utilizando los nuevos controles .NET PerformanceCounter.

Tras la instalación de .NET Framework v4.6.1, nuestras conexiones a una base de datos remota comenzaron inmediatamente el tiempo de espera debido a este cambio .

Para solucionarlo simplemente agregue el parámetro TransparentNetworkIPResolution en la cadena de conexión y configúrelo en falso :

Server = myServerName; Database = myDataBase; Trusted_Connection = True; TransparentNetworkIPResolution = False

A menos que su uso aumente mucho, parece poco probable que exista un retraso en el trabajo. OMI, la opción más probable es que algo esté usando conexiones y no las libere con prontitud. ¿Estás seguro de que estás using en todos los casos? ¿O (a través de cualquier mecanismo) liberando las conexiones?

¿Revisó DataReaders que no están cerrados y response.redirects antes de cerrar la conexión o un lector de datos? Las conexiones permanecen abiertas cuando no las cierra antes de una redirección.

También encontramos este problema de vez en cuando en nuestro sitio web. El culpable en nuestro caso es que nuestras estadísticas / índices están desactualizados. Esto hace que una consulta que se ejecuta con anterioridad se vuelva lenta y eventualmente lenta.

Intenta actualizar estadísticas y / o reconstruir los índices en las tablas afectadas por la consulta y ver si eso ayuda.

Puede especificar el tamaño mínimo y máximo de la agrupación especificando MinPoolSize=xyz y / o MaxPoolSize=xyz en la cadena de conexión. Sin embargo, esta causa del problema podría ser una cosa diferente.

También me he encontrado con este problema cuando uso una capa de datos de terceros en una de mis aplicaciones .NET. El problema fue que la capa no cerró las conexiones correctamente.

Tiramos la capa y creamos una, que siempre cierra y desecha las conexiones. Desde entonces ya no obtenemos el error.

Si está trabajando en un código heredado complejo en el que no es posible utilizar (..) {..} simplemente – como yo lo estaba haciendo – puede que desee verificar el fragmento de código que publiqué en esta pregunta SO para conocer el modo de determinar el la stack de llamadas de la creación de la conexión cuando una conexión se puede filtrar (no se cierra después de un tiempo de espera establecido). Esto hace que sea bastante fácil detectar la causa de las fugas.

Esto se debe principalmente a que la conexión no se ha cerrado en la aplicación. Use “MinPoolSize” y “MaxPoolSize” en la cadena de conexión.

En mi caso, no estaba cerrando el objeto DataReader.

  using (SqlCommand dbCmd = new SqlCommand("*StoredProcedureName*")) using (dbCmd.Connection = new SqlConnection(WebConfigurationAccess.ConnectionString)) { dbCmd.CommandType = CommandType.StoredProcedure; //Add parametres dbCmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.Int)).Value = ID; ..... ..... dbCmd.Connection.Open(); var dr = dbCmd.ExecuteReader(); //created a Data reader here dr.Close(); //gotta close the data reader //dbCmd.Connection.Close(); //don't need this as 'using' statement should take care of this in its implicit dispose method. } 

No instanciar la conexión sql muchas veces. Abra una o dos conexiones y úselos para todas las próximas operaciones sql.

Parece que incluso cuando se Dispose las conexiones, se lanza la excepción.

Utilizar esta:

 finally { connection.Close(); connection.Dispose(); SqlConnection.ClearPool(); } 

Puedes probar eso también, para resolver el problema del tiempo de espera:

Si no agregó httpRuntime a su webconfig, agréguelo en la etiqueta

    

y

Modifique su cadena de conexión de esta manera;

   

En el último uso

  try {...} catch {...} finaly { connection.close(); } 

Este problema lo tuve en mi código. Voy a pegar un código de ejemplo que tengo más vino por debajo del error. 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.

  String query = "insert into STATION2(ID,CITY,STATE,LAT_N,LONG_W) values('" + a1 + "','" + b1 + "','" + c1 + "','" + d1 + "','" + f1 + "')"; //,'" + d1 + "','" + f1 + "','" + g1 + "' SqlConnection con = new SqlConnection(mycon); con.Open(); SqlCommand cmd = new SqlCommand(); cmd.CommandText = query; cmd.Connection = con; cmd.ExecuteNonQuery(); **con.Close();** 

Desea cerrar la conexión todas y cada una de las veces. Antes de eso, nosotros no nos conectamos porque tenía un error. Después de agregar el enunciado cerrado que tuve sobre vino este error

Además de las soluciones publicadas …

Al tratar con 1000 páginas de código heredado, cada una llamando a un GetRS común varias veces, aquí hay otra manera de solucionar el problema:

En una DLL común existente, agregamos la opción CommandBehavior.CloseConnection :

  static public IDataReader GetRS(String Sql) { SqlConnection dbconn = new SqlConnection(DB.GetDBConn()); dbconn.Open(); SqlCommand cmd = new SqlCommand(Sql, dbconn); return cmd.ExecuteReader(CommandBehavior.CloseConnection); } 

Luego, en cada página, siempre que cierre el lector de datos, la conexión también se cerrará automáticamente para evitar pérdidas de conexión.

  IDataReader rs = CommonDLL.GetRS("select * from table"); while (rs.Read()) { // do something } rs.Close(); // this also closes the connection 

Has filtrado conexiones en tu código. Puede intentar usar para certificar que los está cerrando.

  Using (SqlConnection sqlconnection1 = new SqlConnection(“Server=.\\SQLEXPRESS ;Integrated security=sspi;connection timeout=5”)) { sqlconnection1.Open(); SqlCommand sqlcommand1 = sqlconnection1.CreateCommand(); sqlcommand1.CommandText = “raiserror ('This is a fake exception', 17,1)”; sqlcommand1.ExecuteNonQuery(); //this throws a SqlException every time it is called. sqlconnection1.Close(); //Still never gets called. } // Here sqlconnection1.Dispose is _guaranteed_ 

https://blogs.msdn.microsoft.com/angelsb/2004/08/25/connection-pooling-and-the-timeout-expired-exception-faq/

Este problema que he encontrado antes. Terminó siendo un problema con el firewall. Acabo de agregar una regla al firewall. Tuve que abrir el puerto 1433 para que el servidor SQL pueda conectarse al servidor.