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

Observer-Overhead- und Wait-Typ-Symptome

Viele Leute verwenden Wartestatistiken als Teil ihrer Methodik zur Fehlerbehebung bei der Gesamtleistung, so wie ich es auch tue, also dreht sich die Frage, die ich in diesem Beitrag untersuchen wollte, um Wartetypen, die mit Beobachter-Overhead verbunden sind. Mit Beobachter-Overhead meine ich die Auswirkungen auf den Arbeitslastdurchsatz von SQL Server, die durch SQL Profiler, serverseitige Ablaufverfolgungen oder Sitzungen mit erweiterten Ereignissen verursacht werden. Weitere Informationen zum Thema Beobachter-Overhead finden Sie in den folgenden beiden Beiträgen meines Kollegen Jonathan Kehayias :

  • Messung des „Beobachter-Overheads“ von SQL Trace im Vergleich zu erweiterten Ereignissen
  • Auswirkung des erweiterten Ereignisses query_post_execution_showplan in SQL Server 2012

In diesem Beitrag möchte ich also einige Variationen des Beobachter-Overheads durchgehen und sehen, ob wir konsistente Wartetypen finden können, die mit der gemessenen Verschlechterung verbunden sind. Es gibt eine Vielzahl von Möglichkeiten, wie SQL Server-Benutzer die Ablaufverfolgung in ihren Produktionsumgebungen implementieren, daher können Ihre Ergebnisse variieren, aber ich wollte einige allgemeine Kategorien abdecken und über das berichten, was ich gefunden habe:

  • Nutzung der SQL Profiler-Sitzung
  • Serverseitige Trace-Nutzung
  • Serverseitige Ablaufverfolgung, Schreiben in einen langsamen E/A-Pfad
  • Verwendung von erweiterten Ereignissen mit einem Ringpufferziel
  • Verwendung von erweiterten Ereignissen mit einem Dateiziel
  • Verwendung von erweiterten Ereignissen mit einem Dateiziel auf einem langsamen E/A-Pfad
  • Verwendung von erweiterten Ereignissen mit einem Dateiziel auf einem langsamen E/A-Pfad ohne Ereignisverlust

Sie können sich wahrscheinlich andere Variationen des Themas ausdenken, und ich lade Sie ein, alle interessanten Erkenntnisse in Bezug auf Beobachter-Overhead und Wartestatistiken als Kommentar in diesem Beitrag zu teilen.

Grundlage

Für den Test habe ich eine virtuelle VMware-Maschine mit vier vCPUs und 4 GB RAM verwendet. Mein virtueller Maschinengast war auf OCZ Vertex SSDs. Das Betriebssystem war Windows Server 2008 R2 Enterprise und die Version von SQL Server ist 2012, SP1 CU4.

Was die „Arbeitslast“ betrifft, verwende ich eine schreibgeschützte Abfrage in einer Schleife für die Beispieldatenbank von 2008 Credit, die 10.000.000 Mal auf GO gesetzt wurde.

USE [Credit];
GO
 
SELECT TOP 1 
     [member].[member_no],
     [member].[lastname],
     [payment].[payment_no],
     [payment].[payment_dt],
     [payment].[payment_amt]
FROM [dbo].[payment]
INNER JOIN [dbo].[member]
ON [member].[member_no] = [payment].[member_no];
GO 10000000

Ich führe diese Abfrage auch über 16 gleichzeitige Sitzungen aus. Das Endergebnis auf meinem Testsystem ist eine CPU-Auslastung von 100 % über alle vCPUs auf dem virtuellen Gast und durchschnittlich 14.492 Batch-Anfragen pro Sekunde über einen Zeitraum von 2 Minuten.

In Bezug auf die Ereignisverfolgung habe ich in jedem Test das Showplan XML Statistics Profile verwendet für die SQL Profiler- und serverseitigen Ablaufverfolgungstests – und query_post_execution_showplan für erweiterte Event-Sessions. Ausführungsplan-Ereignisse sind sehr teuer, genau deshalb habe ich sie gewählt, damit ich sehen kann, ob ich unter extremen Umständen Wartetypen-Themes ableiten kann oder nicht.

Zum Testen der Akkumulation des Wartetyps über einen Testzeitraum habe ich die folgende Abfrage verwendet. Nichts Besonderes – einfach die Statistiken löschen, 2 Minuten warten und dann die 10 höchsten Wartezeiten für die SQL Server-Instanz während des Verschlechterungstestzeitraums sammeln:

-- Clearing the wait stats
 
DBCC SQLPERF('waitstats', clear);
 
WAITFOR DELAY '00:02:00';
GO
 
SELECT TOP 10
     [wait_type],
     [waiting_tasks_count],
     [wait_time_ms]
FROM sys.[dm_os_wait_stats] AS [ws]
ORDER BY [wait_time_ms] DESC;

Beachten Sie, dass ich nicht bin Herausfiltern von Wartetypen im Hintergrund, die normalerweise herausgefiltert werden, und das liegt daran, dass ich etwas nicht eliminieren wollte, das normalerweise harmlos ist – aber unter diesen Umständen weist es tatsächlich auf einen echten Bereich hin, der weiter untersucht werden muss.

SQL Profiler-Sitzung

Die folgende Tabelle zeigt die Vorher-Nachher-Stapelanforderungen pro Sekunde, wenn ein lokales SQL Profiler-Trace-Tracking Showplan XML Statistics Profile aktiviert wird (läuft auf derselben VM wie die SQL Server-Instanz):

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Sitzungs-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 1.416

Sie können sehen, dass der SQL Profiler-Trace einen erheblichen Durchsatzabfall verursacht.

Was die kumulierte Wartezeit über denselben Zeitraum anbelangt, waren die wichtigsten Wartetypen wie folgt (wie bei den restlichen Tests in diesem Artikel habe ich einige Testläufe durchgeführt und die Ausgabe war im Allgemeinen konsistent):

wait_type waiting_tasks_count wait_time_ms
TRACEWRITE 67.142 1.149.824
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.003
SLEEP_TASK 313 180.449
REQUEST_FOR_DEADLOCK_SEARCH 24 120.111
HADR_FILESTREAM_IOMGR_IOCOMPLETION 240 120.086
LAZYWRITER_SLEEP 120 120.059
DIRTY_PAGE_POLL 1.198 120.038
HADR_WORK_QUEUE 12 120.015
LOGMGR_QUEUE 937 120.011
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.006

Der Wartetyp, der mir auffällt, ist TRACEWRITE – der von der Onlinedokumentation als ein Wartetyp definiert wird, der „auftritt, wenn der Rowset-Ablaufverfolgungsanbieter der SQL-Ablaufverfolgung entweder auf einen freien Puffer oder einen Puffer mit zu verarbeitenden Ereignissen wartet“. Die restlichen Wartetypen sehen aus wie standardmäßige Wartetypen im Hintergrund, die normalerweise aus Ihrer Ergebnismenge herausgefiltert werden. Darüber hinaus habe ich 2011 in einem Artikel mit dem Titel „Observer Overhead“ über ein ähnliches Problem mit übermäßiger Ablaufverfolgung gesprochen – die Gefahren einer zu langen Ablaufverfolgung –, sodass ich mit diesem Wartetyp manchmal vertraut war richtig auf Beobachter-Overhead-Probleme hindeutet. Nun, in diesem speziellen Fall, über den ich gebloggt habe, war es nicht SQL Profiler, sondern eine andere Anwendung, die den Rowset-Trace-Provider (ineffizient) verwendet.

Serverseitige Ablaufverfolgung

Das war für SQL Profiler, aber was ist mit dem serverseitigen Trace-Overhead? Die folgende Tabelle zeigt die Vorher-Nachher-Stapelanforderungen pro Sekunde, wenn ein lokaler serverseitiger Trace zum Schreiben in eine Datei aktiviert wird:

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 4.015

Die wichtigsten Wartetypen waren wie folgt (ich habe ein paar Testläufe durchgeführt und die Ausgabe war konsistent):

wait_type waiting_tasks_count wait_time_ms
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.015
SLEEP_TASK 253 180.871
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.046
HADR_WORK_QUEUE 12 120.042
REQUEST_FOR_DEADLOCK_SEARCH 24 120.021
XE_DISPATCHER_WAIT 3 120.006
WARTEN 1 120.000
LOGMGR_QUEUE 931 119.993
DIRTY_PAGE_POLL 1.193 119.958
XE_TIMER_EVENT 55 119.954

Dieses Mal sehen wir TRACEWRITE nicht (wir verwenden jetzt einen Dateianbieter) und den anderen ablaufverfolgungsbezogenen Wartetyp, den undokumentierten SQLTRACE_INCREMENTAL_FLUSH_SLEEP gestiegen – hat aber im Vergleich zum ersten Test eine sehr ähnliche akkumulierte Wartezeit (120.046 vs. 120.006) – und meine Kollegin Erin Stellato (@erinstellato) hat in ihrem Beitrag „Finding Out When Wait Statistics were last cleared“ über diesen speziellen Wartetyp gesprochen . Wenn man sich also die anderen Wartetypen ansieht, springt keiner als zuverlässiges Warnsignal heraus.

Serverseitige Ablaufverfolgung schreibt in einen langsamen E/A-Pfad

Was passiert, wenn wir die serverseitige Ablaufverfolgungsdatei auf eine langsame Festplatte legen? Die folgende Tabelle zeigt die Vorher-Nachher-Batch-Anforderungen pro Sekunde, wenn eine lokale serverseitige Ablaufverfolgung aktiviert wird, die in eine Datei auf einem USB-Stick schreibt:

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 260

Wie wir sehen, hat sich die Leistung deutlich verschlechtert – sogar im Vergleich zum vorherigen Test.

Die häufigsten Wartetypen waren wie folgt:

wait_type waiting_tasks_count wait_time_ms
SQLTRACE_FILE_BUFFER 357 351.174
SP_SERVER_DIAGNOSTICS_SLEEP 2.273 299.995
SLEEP_TASK 240 194.264
FT_IFTS_SCHEDULER_IDLE_WAIT 2 181.458
REQUEST_FOR_DEADLOCK_SEARCH 25 125.007
LAZYWRITER_SLEEP 63 124.437
LOGMGR_QUEUE 941 120.559
HADR_FILESTREAM_IOMGR_IOCOMPLETION 67 120.516
WARTEN 1 120.515
DIRTY_PAGE_POLL 1.204 120.513

Ein Wartetyp, der für diesen Test herausspringt, ist der undokumentierte SQLTRACE_FILE_BUFFER . Nicht viel dokumentiert, aber basierend auf dem Namen können wir eine fundierte Vermutung anstellen (insbesondere angesichts der Konfiguration dieses speziellen Tests).

Erweiterte Ereignisse zum Ringpufferziel

Sehen wir uns als Nächstes die Ergebnisse für Sitzungsäquivalente für erweiterte Ereignisse an. Ich habe die folgende Sitzungsdefinition verwendet:

CREATE EVENT SESSION [ApplicationXYZ] ON SERVER
  ADD EVENT sqlserver.query_post_execution_showplan,
  ADD TARGET package0.ring_buffer(SET max_events_limit=(1000))
  WITH (STARTUP_STATE=ON);
GO

Die folgende Tabelle zeigt die Vorher-Nachher-Stapelanforderungen pro Sekunde, wenn eine XE-Sitzung mit einem Ringpufferziel aktiviert wird (Erfassen des query_post_execution_showplan Ereignis):

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 4.737

Die häufigsten Wartetypen waren wie folgt:

wait_type waiting_tasks_count wait_time_ms
SP_SERVER_DIAGNOSTICS_SLEEP 612 299.992
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.006
SLEEP_TASK 240 181.739
LAZYWRITER_SLEEP 120 120.219
HADR_WORK_QUEUE 12 120.038
DIRTY_PAGE_POLL 1.198 120.035
REQUEST_FOR_DEADLOCK_SEARCH 24 120.017
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.011
LOGMGR_QUEUE 936 120.008
WARTEN 1 120.001

Nichts sprang als XE-bezogen heraus, nur "Rauschen" der Hintergrundaufgabe.

Erweiterte Ereignisse zu einem Dateiziel

Was ist mit dem Ändern der Sitzung, um ein Dateiziel anstelle eines Ringpufferziels zu verwenden? Die folgende Tabelle zeigt die Vorher-Nachher-Stapelanforderungen pro Sekunde, wenn eine XE-Sitzung mit einem Dateiziel statt einem Ringpufferziel aktiviert wird:

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 4.299

Die häufigsten Wartetypen waren wie folgt:

wait_type waiting_tasks_count wait_time_ms
SP_SERVER_DIAGNOSTICS_SLEEP 2.103 299.996
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.003
SLEEP_TASK 253 180.663
LAZYWRITER_SLEEP 120 120.187
HADR_WORK_QUEUE 12 120.029
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.019
REQUEST_FOR_DEADLOCK_SEARCH 24 120.011
WARTEN 1 120.001
XE_TIMER_EVENT 59 119.966
LOGMGR_QUEUE 935 119.957

Nichts, mit Ausnahme von XE_TIMER_EVENT , sprang als XE-bezogen heraus. Das Wait Type Repository von Bob Ward weist darauf hin, dass dieser Typ sicher ignoriert werden kann, es sei denn, es liegt ein möglicher Fehler vor – aber würden Sie diesen normalerweise harmlosen Wartetyp realistischerweise bemerken, wenn er während einer Leistungsminderung an 9. Stelle auf Ihrem System wäre? Und was ist, wenn Sie es aufgrund seiner normalerweise harmlosen Natur bereits herausfiltern?

Erweiterte Ereignisse zu einem langsamen E/A-Pfaddateiziel

Was passiert nun, wenn ich die Datei auf einen langsamen E/A-Pfad lege? Die folgende Tabelle zeigt die Vorher-Nachher-Stapelanforderungen pro Sekunde beim Aktivieren einer XE-Sitzung mit einem Dateiziel auf einem USB-Stick:

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 4.386

Die häufigsten Wartetypen waren wie folgt:

wait_type waiting_tasks_count wait_time_ms
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.046
SLEEP_TASK 253 180.719
HADR_FILESTREAM_IOMGR_IOCOMPLETION 240 120.427
LAZYWRITER_SLEEP 120 120.190
HADR_WORK_QUEUE 12 120.025
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.013
REQUEST_FOR_DEADLOCK_SEARCH 24 120.011
WARTEN 1 120.002
DIRTY_PAGE_POLL 1.197 119.977
XE_TIMER_EVENT 59 119.949

Wieder springt nichts XE-bezogenes heraus, außer dem XE_TIMER_EVENT .

Erweiterte Ereignisse zu einem langsamen E/A-Pfaddateiziel, kein Ereignisverlust

Die folgende Tabelle zeigt die Vorher-Nachher-Batch-Anforderungen pro Sekunde beim Aktivieren einer XE-Sitzung mit einem Dateiziel auf einem USB-Stick, diesmal jedoch ohne Ereignisverlust (EVENT_RETENTION_MODE=NO_EVENT_LOSS) – was nicht empfohlen wird, und Sie werden sehen in den Ergebnissen, warum das sein könnte:

Baseline-Batch-Anforderungen pro Sekunde
(2-Minuten-Durchschnitt)
SQL Profiler-Batch-Anfragen pro Sekunde
(2-Minuten-Durchschnitt)
14.492 539

Die häufigsten Wartetypen waren wie folgt:

wait_type waiting_tasks_count wait_time_ms
XE_BUFFERMGR_FREEBUF_EVENT 8.773 1.707.845
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.003
SLEEP_TASK 337 180.446
LAZYWRITER_SLEEP 120 120.032
DIRTY_PAGE_POLL 1.198 120.026
HADR_WORK_QUEUE 12 120.009
REQUEST_FOR_DEADLOCK_SEARCH 24 120.007
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.006
WARTEN 1 120.000
XE_TIMER_EVENT 59 119.944

Bei der extremen Durchsatzreduzierung sehen wir XE_BUFFERMGR_FREEBUF_EVENT Springen Sie in unseren kumulierten Wartezeitergebnissen auf Platz eins. Dieser ist dokumentiert in Books Online, und Microsoft teilt uns mit, dass dieses Ereignis XE-Sitzungen zugeordnet ist, die für keinen Ereignisverlust konfiguriert sind und bei denen alle Puffer in der Sitzung voll sind.

Beobachtereinfluss

Abgesehen von Wartetypen war es interessant festzustellen, welche Auswirkungen jede Beobachtungsmethode auf die Fähigkeit unserer Workload hatte, Stapelanfragen zu verarbeiten:


Auswirkung verschiedener Beobachtungsmethoden auf Batch-Anfragen pro Sekunde

Bei allen Ansätzen gab es einen signifikanten – aber nicht schockierenden – Treffer im Vergleich zu unserer Basislinie (keine Beobachtung); Die größten Probleme traten jedoch bei der Verwendung von Profiler auf, bei der Verwendung von serverseitigem Trace für einen langsamen E/A-Pfad oder erweiterten Ereignissen für ein Dateiziel auf einem langsamen E/A-Pfad – aber nur, wenn es für keinen Ereignisverlust konfiguriert war. Beim Ereignisverlust war dieses Setup tatsächlich auf Augenhöhe mit einem Dateiziel für einen schnellen E/A-Pfad, vermutlich weil es viel mehr Ereignisse verwerfen konnte.

Zusammenfassung

Ich habe nicht jedes mögliche Szenario getestet, und es gibt sicherlich andere interessante Kombinationen (ganz zu schweigen von unterschiedlichen Verhaltensweisen, die auf der SQL Server-Version basieren), aber die wichtigste Schlussfolgerung, die ich aus dieser Untersuchung ziehe, ist, dass Sie sich nicht immer auf eine offensichtliche Akkumulation des Wartetyps verlassen können Zeiger, wenn man einem Betrachter-Overhead-Szenario gegenübersteht. Basierend auf den Tests in diesem Beitrag zeigten nur drei von sieben Szenarien einen bestimmten Wartetyp, der Ihnen möglicherweise helfen könnte, in die richtige Richtung zu weisen. Schon damals – diese Tests fanden auf einem kontrollierten System statt – und häufig filtern die Leute die oben genannten Wartetypen als harmlose Hintergrundtypen heraus – sodass Sie sie möglicherweise überhaupt nicht sehen.

Was können Sie in Anbetracht dessen tun? Bei Leistungseinbußen ohne klare oder offensichtliche Symptome empfehle ich, den Bereich zu erweitern, um nach Ablaufverfolgungen und XE-Sitzungen zu fragen (nebenbei – ich empfehle auch, Ihren Bereich zu erweitern, wenn das System virtualisiert ist oder möglicherweise falsche Energieoptionen hat). Überprüfen Sie beispielsweise im Rahmen der Fehlerbehebung in einem System sys.[traces] und sys.[dm_xe_sessions] um zu sehen, ob etwas Unerwartetes auf dem System läuft. Es ist eine zusätzliche Ebene zu dem, worüber Sie sich Sorgen machen müssen, aber wenn Sie ein paar schnelle Überprüfungen durchführen, können Sie viel Zeit sparen.