web-dev-qa-db-fra.com

Actuellement, toutes les connexions obtiennent le «Délai d'expiration»

J'ai une application qui se connecte à SQL Server. Actuellement, je reçois,

Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.

Quand j'ai couru,

SELECT 
    DB_NAME(dbid) as DBName, 
    COUNT(dbid) as NumberOfConnections,
    loginame as LoginName
FROM
    sys.sysprocesses
WHERE 
     DB_NAME(dbid) ='MyDb'
GROUP BY 
    dbid, loginame 

DBName  NumberOfConnections LoginName
MyDb    10                     sa                                                                                                                              
MyDb    109                   MyUser

Le statut de tous les processus est sleeping et cms est AWAITING COMMAND

Voici mon code,

private async Task<object> ExecuteAsync<T>(ExecutionType executionType, CommandType commandType, string commandText, IsolationLevel isolationLevel, SqlParameter[] parameters, Func<IDataReader, T> callback = null)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    using (var connection = new SqlConnection(_settings.DatabaseConnectionString))
    {
        using (var command = new SqlCommand(commandText, connection) {CommandType = commandType})
        {
            command.Parameters.AddRange(parameters);
            await connection.OpenAsync().ConfigureAwait(false);
            command.CommandTimeout = _settings.CommandTimeout;
            var transaction = connection.BeginTransaction(isolationLevel);
            command.Transaction = transaction;
            try
            {
                object result;
                switch (executionType)
                {
                    case ExecutionType.Reader:
                        var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);
                        using (reader)
                        {
                            var list = new List<T>();
                            while (reader.Read())
                            {
                                if (callback != null)
                                {
                                    var item = callback(reader);
                                    if (item != null)
                                    {
                                        list.Add(item);
                                    }
                                }
                            }
                            result = list;
                        }
                        break;
                    case ExecutionType.NonQuery:
                        result = await command.ExecuteNonQueryAsync().ConfigureAwait(false);
                        break;
                    default:
                        result = await command.ExecuteScalarAsync().ConfigureAwait(false);
                        break;
                }
                transaction.Commit();
                stopwatch.Stop();
                var elapsed = stopwatch.Elapsed;
                if (elapsed.Seconds > 2)
                {
                    _logger.Log(string.Format("{0} took {1} time", command.CommandText, elapsed));// only log if it tooks more than 2 seconds
                }
                return result;
            }
            catch (Exception exception)
            {
                _logger.Log(exception);
                transaction.Rollback();
                throw;
            }
        }
    }
}
4
user960567

Il semble que vous ayez une application qui ne ferme pas ou ne supprime pas correctement les objets SqlConnection. Par défaut, SqlConnection a une taille maximale de pool de 1 .

Le correctif serait de travailler avec l'application pour savoir pourquoi les connexions ne sont pas nettoyées, car elles sont toujours "actives" dans le pool de connexions particulier, c'est pourquoi vous ne pouvez pas en saisir une autre, car il n'y a pas connexions inactives dans le pool à utiliser.

L'application doit effectuer un appel à SqlConnection.Close() ou SqlConnection.Dispose() afin de libérer la connexion et de la marquer comme "inactive".

J'ai écrit un vaste article de blog ( Pooling de connexions pour le DBA SQL Server ) sur le pool de connexions , et cela devrait faire la lumière pourquoi vous voyez ce que vous voyez, ainsi que la correction programmatique du problème.

8
Thomas Stringer

Une alternative est que si vous traitez un volume plus élevé d'enregistrements, vous pouvez en fait obtenir une erreur trompeuse. Il se peut que vous ayez utilisé tous vos ports sur votre PC, vous pouvez le vérifier en exécutant Sysinternals TCPView .

Si vous voyez des milliers de TIME_WAIT , c'est une cause possible.

En substance, une fois que votre application a fermé sa connexion à la base de données (à la fin de using (var connection = new SqlConnection(_settings.DatabaseConnectionString))), TCP attendra près de 4 minutes avant que le port utilisé était libre de être utilisé à nouveau.

De la mémoire, vous devez traiter environ 16 000 exécutions en moins de 4 minutes pour que cela se produise (cela dépendra de la version de votre système d'exploitation et de ce que vous avez d'autre sur ce PC).

5
Andrew Bickerton