Autore ospite:Michael J Swart (@MJSwart)
Di recente siamo stati sorpresi da una serie di eccezioni lanciate dalla nostra applicazione. La nostra applicazione non funzionava durante il tentativo di aprire un SqlConnection. Le eccezioni si presentavano così:
Errore System.InvalidOperationException:Timeout scaduto. Il periodo di timeout è trascorso prima di ottenere una connessione dal pool. Ciò potrebbe essersi verificato perché tutte le connessioni in pool erano in uso ed è stata raggiunta la dimensione massima del pool.
Pool di connessione
Ricorda che .Net utilizza i pool di connessioni per evitare il sovraccarico di stabilire una connessione su ogni query. I pool di connessione vengono gestiti per ogni stringa di connessione e per impostazione predefinita il numero di connessioni nel pool è limitato a cento. Di solito sono sufficienti cento connessioni. Non abbiamo mai avuto problemi con questa eccezione prima e i nostri server non erano più occupati del solito, quindi eravamo riluttanti ad aumentare il valore di MaxPoolSize. Abbiamo iniziato a sospettare perdite di connessione al database.
Perdite di connessione al database
Proprio come le perdite di memoria, possono verificarsi perdite di connessione al database se non si eliminano le connessioni al database in modo tempestivo. SqlConnections sono IDisposable, quindi è consigliabile utilizzare l'istruzione using:
using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); // etc... }
Non appena hai finito con SqlConnection, viene eliminato e la connessione effettiva ritorna immediatamente al pool di connessioni in modo che possa essere utilizzata da qualcun altro. In caso contrario, la connessione rimane in uso fino al termine del processo o fino a quando la raccolta dei rifiuti non la ripulisce.
Trovare le perdite di connessione
Pertanto, se l'applicazione presenta timeout di connessione a causa di una perdita di connessione al database, le tracce dello stack potrebbero non essere di aiuto. Proprio come un'eccezione di memoria insufficiente a causa di una perdita di memoria, la traccia dello stack contiene informazioni sulla vittima, ma non sulla causa principale. Quindi, dove puoi trovare la perdita?
Anche se le perdite di connessione al database sono un problema del client, puoi trovare aiuto dal server del database. Sul server di database, esamina le connessioni per processo per database per ottenere una stima approssimativa delle dimensioni di ciascun pool:
select count(*) as sessions, s.host_name, s.host_process_id, s.program_name, db_name(s.database_id) as database_name from sys.dm_exec_sessions s where is_user_process = 1 group by host_name, host_process_id, program_name, database_id order by count(*) desc;
Il nome del programma, il nome dell'host, l'ID del processo e il nome del database sono generalmente sufficienti per identificare le connessioni provenienti dallo stesso pool di connessioni.
Questo mi porta a porre qualche altra domanda sui pool con molte connessioni. Dato un pool, ci sono sessioni che sono state inattive per un po' e, in tal caso, da quanto tempo sono state inattive e qual è stata l'ultima istruzione SQL che hanno eseguito?
declare @host_process_id int = 1508; declare @host_name sysname = N'SERV4102'; declare @database_name sysname = N'My_Database'; select datediff(minute, s.last_request_end_time, getdate()) as minutes_asleep, s.session_id, db_name(s.database_id) as database_name, s.host_name, s.host_process_id, t.text as last_sql, s.program_name from sys.dm_exec_connections c join sys.dm_exec_sessions s on c.session_id = s.session_id cross apply sys.dm_exec_sql_text(c.most_recent_sql_handle) t where s.is_user_process = 1 and s.status = 'sleeping' and db_name(s.database_id) = @database_name and s.host_process_id = @host_process_id and s.host_name = @host_name and datediff(second, s.last_request_end_time, getdate()) > 60 order by s.last_request_end_time;
Il testo può ora essere utilizzato per cercare la base di codice della tua applicazione per trovare dove potresti avere una perdita di connessione al database.
Queste query sono utili per la risoluzione di una perdita di connessione al database e possono essere utilizzate anche per creare un monitoraggio o un controllo dello stato.
Smaltisci i tuoi usa e getta, usa quegli usi, sigilla quelle perdite!