Database
 sql >> Datenbank >  >> RDS >> Database

Finden Sie Datenbankverbindungslecks in Ihrer Anwendung

Gastautor:Michael J Swart (@MJSwart)

Wir waren kürzlich von einer Reihe von Ausnahmen überrascht, die unsere Anwendung ausgelöst hat. Unsere Anwendung ist beim Versuch, eine SqlConnection zu öffnen, fehlgeschlagen. Die Ausnahmen sahen so aus:

Fehler System.InvalidOperationException:

Zeitüberschreitung. Das Zeitlimit ist abgelaufen, bevor eine Verbindung vom Pool hergestellt wurde. Dies ist möglicherweise aufgetreten, weil alle gepoolten Verbindungen verwendet wurden und die maximale Poolgröße erreicht wurde.

Verbindungspools

Denken Sie daran, dass .Net Verbindungspools verwendet, um den Aufwand für das Herstellen einer Verbindung bei jeder Abfrage zu vermeiden. Verbindungspools werden für jede Verbindungszeichenfolge verwaltet, und standardmäßig ist die Anzahl der Verbindungen im Pool auf 100 begrenzt. Einhundert Verbindungen sind in der Regel ausreichend. Wir hatten noch nie ein Problem mit dieser Ausnahme und unsere Server waren nicht stärker ausgelastet als sonst, daher zögerten wir, den Wert von MaxPoolSize zu erhöhen. Wir begannen, Datenbankverbindungslecks zu vermuten.
 

Datenbankverbindungslecks

Genau wie Speicherlecks können Datenbankverbindungslecks auftreten, wenn Sie Ihre Datenbankverbindungen nicht rechtzeitig beseitigen. SqlConnections sind IDisposable, daher empfiehlt es sich, die using-Anweisung zu verwenden:

using (SqlConnection conn = new SqlConnection(connectionString)) 
{
  conn.Open();
  // etc...
}

Sobald Sie mit der SqlConnection fertig sind, wird sie verworfen und die eigentliche Verbindung kehrt sofort zum Verbindungspool zurück, damit sie von jemand anderem verwendet werden kann. Andernfalls bleibt die Verbindung in Gebrauch, bis der Prozess endet oder die Garbage Collection sie bereinigt.

Ihre Verbindungslecks finden

Wenn es bei Ihrer Anwendung also zu Verbindungszeitüberschreitungen aufgrund eines Datenbankverbindungslecks kommt, helfen Ihnen die Stack-Traces möglicherweise nicht weiter. Genau wie eine Out-of-Memory-Ausnahme aufgrund eines Speicherlecks enthält der Stack-Trace Informationen über das Opfer, aber nicht die Grundursache. Wo können Sie also nach dem Leck suchen?
 
Obwohl Lecks in Datenbankverbindungen ein Client-Problem sind, können Sie Hilfe vom Datenbankserver erhalten. Sehen Sie sich auf dem Datenbankserver die Verbindungen pro Prozess und Datenbank an, um eine grobe Schätzung der Größe jedes Pools zu erhalten:

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;

Programmname, Hostname, Prozess-ID und Datenbankname sind normalerweise gut genug, um Verbindungen aus demselben Verbindungspool zu identifizieren.

Das bringt mich dazu, ein paar weitere Fragen zu Pools mit vielen Verbindungen zu stellen. Gibt es bei einem Pool Sitzungen, die eine Weile geschlafen haben, und wenn ja, wie lange haben sie geschlafen und was war die letzte SQL-Anweisung, die sie ausgeführt haben?

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;

Der Text kann nun verwendet werden, um die Codebasis Ihrer Anwendung zu durchsuchen, um herauszufinden, wo möglicherweise ein Datenbankverbindungsleck vorliegt.

Diese Abfragen sind nützlich, um ein Datenbankverbindungsleck zu beheben, und sie können auch zum Erstellen eines Monitors oder einer Zustandsprüfung verwendet werden.

Entsorgen Sie Ihre Einwegartikel, verwenden Sie diese Verwendungen, dichten Sie diese Lecks ab!

Über den Autor

Michael J Swart ist ein leidenschaftlicher Datenbankexperte und Blogger, der sich auf Datenbankentwicklung und Softwarearchitektur konzentriert. Er spricht gerne über alles, was mit Daten zu tun hat, und trägt zu Gemeinschaftsprojekten bei. Michael bloggt als „Database Whisperer“ auf michaeljswart.com.