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

Einführung in Latches

In einigen meiner vorherigen Artikel hier zur Leistungsoptimierung habe ich mehrere Wartetypen besprochen und wie sie auf verschiedene Ressourcenengpässe hinweisen. Ich beginne eine neue Serie über Szenarien, in denen ein als Latch bezeichneter Synchronisierungsmechanismus einen Leistungsengpass darstellt, und insbesondere Nicht-Seiten-Latches. In diesem ersten Beitrag werde ich erklären, warum Latches erforderlich sind, was sie eigentlich sind und wie sie ein Engpass sein können.

Warum werden Riegel benötigt?

Es ist ein grundlegender Grundsatz der Informatik, dass immer dann, wenn eine Datenstruktur in einem Multithread-System vorhanden ist, die Datenstruktur auf irgendeine Weise geschützt werden muss. Dieser Schutz enthält die folgenden Vorbehalte:

  1. (Garantiert) Eine Datenstruktur kann nicht von einem Thread geändert werden, während ein anderer Thread sie liest
  2. (Garantiert) Eine Datenstruktur kann nicht von einem Thread gelesen werden, während ein anderer Thread sie ändert
  3. (Garantiert) Eine Datenstruktur kann nicht von zwei oder mehr Threads gleichzeitig geändert werden
  4. (Optional) Zwei oder mehr Threads erlauben, die Datenstruktur gleichzeitig zu lesen
  5. (Optional) Threads erlauben, sich in geordneter Weise für den Zugriff auf die Datenstruktur in die Warteschlange einzureihen

Dies kann auf verschiedene Arten erfolgen, einschließlich:

  • Ein Mechanismus, der immer nur einem einzelnen Thread Zugriff auf die Datenstruktur gewährt. SQL Server implementiert diesen Mechanismus und nennt ihn Spinlock. Dies erlaubt #1, #2 und #3 oben.
  • Ein Mechanismus, der es mehreren Threads ermöglicht, die Datenstruktur gleichzeitig zu lesen (d. h. sie haben gemeinsamen Zugriff), einem einzelnen Thread den exklusiven Zugriff auf die Datenstruktur ermöglicht (unter Ausschluss aller anderen Threads) und implementiert eine faire Möglichkeit, sich für den Zugang anzustellen. SQL Server implementiert diesen Mechanismus und nennt ihn Latch. Dies ermöglicht alle fünf oben genannten Vorbehalte.

Warum verwendet SQL Server also sowohl Spinlocks als auch Latches? Auf einige Datenstrukturen wird so häufig zugegriffen, dass ein Latch einfach zu teuer ist und stattdessen ein sehr leichtgewichtiger Spinlock verwendet wird. Zwei Beispiele für solche Datenstrukturen sind die Liste der freien Puffer im Pufferpool und die Liste der Sperren im Sperrenmanager.

Was ist ein Latch?

Ein Latch ist ein Synchronisierungsmechanismus, der eine einzelne Datenstruktur schützt, und es gibt drei große Arten von Latches in SQL Server:

  1. Latches schützen eine Datendateiseite, während sie von der Festplatte gelesen wird. Diese werden angezeigt, wenn PAGEIOLATCH_XX wartet, und ich habe sie in diesem Beitrag besprochen.
  2. Latches schützen den Zugriff auf eine Datendateiseite, die sich bereits im Speicher befindet (eine 8-KB-Seite im Pufferpool ist wirklich nur eine Datenstruktur). Diese werden angezeigt, während PAGELATCH_XX wartet, und ich habe sie in diesem Beitrag besprochen.
  3. Latches schützen Nicht-Seiten-Datenstrukturen. Diese werden als LATCH_SH- und LATCH_EX-Wartezeiten angezeigt.

In dieser Serie konzentrieren wir uns auf die dritte Art von Verriegelungen.

Ein Latch ist selbst eine kleine Datenstruktur und Sie können sich vorstellen, dass es drei Komponenten hat:

  • Eine Ressourcenbeschreibung (was sie schützt)
  • Ein Statusfeld, das angibt, in welchem ​​Modus sich der Latch derzeit befindet, wie viele Threads den Latch in diesem Modus halten und ob irgendwelche Threads warten (plus andere Dinge, um die wir uns nicht kümmern müssen)
  • Eine First-In-First-Out-Warteschlange von Threads, die auf den Zugriff auf die Datenstruktur warten, und auf welche Zugriffsmodi sie warten (sogenannte Warteschlange)

Für Non-Page-Latches beschränken wir uns darauf, nur die Zugriffsmodi SH (share) zum Lesen der Datenstruktur und EX (exclusive) zum Ändern der Datenstruktur zu betrachten. Es gibt andere exotischere Modi, aber sie werden selten verwendet und werden nicht als Streitpunkt erscheinen, also werde ich für den Rest dieser Diskussion so tun, als ob sie nicht existieren.

Einige von Ihnen wissen vielleicht, dass es auch tiefere Komplikationen bei Superlatches/Sublatches und Latch-Partitionierung für die Skalierbarkeit gibt, aber wir müssen für die Zwecke dieser Serie nicht so tief gehen.

Ein Latch erwerben

Wenn ein Thread einen Latch erwerben möchte, sieht er sich den Status des Latches an.

Wenn der Thread den Latch im EX-Modus erwerben möchte, kann er dies nur tun, wenn es keine Threads gibt, die den Latch in irgendeinem Modus halten. Wenn dies der Fall ist, erwirbt der Thread den Latch im EX-Modus und setzt den Status, um dies anzuzeigen. Wenn es einen oder mehrere Threads gibt, die bereits den Latch halten, setzt der Thread den Status, um anzuzeigen, dass es einen wartenden Thread gibt, trägt sich selbst am Ende der Warteschlange ein und wird dann ausgesetzt (auf der Warteliste des Planers, auf dem er sich befindet ) warten auf LATCH_EX.

Wenn der Thread den Latch im SH-Modus erwerben möchte, kann er dies nur tun, wenn kein Thread den Latch hält oder die einzigen Threads, die den Latch halten, im SH-Modus sind *und* es keine Threads gibt, die darauf warten, den Latch zu erwerben. Wenn dies der Fall ist, ruft der Thread den Latch im SH-Modus ab, setzt den Status, um dies anzuzeigen, und erhöht die Anzahl der Threads, die den Latch halten. Wenn der Latch im EX-Modus gehalten wird oder es einen oder mehrere wartende Threads gibt, dann setzt der Thread den Status, um anzuzeigen, dass es einen wartenden Thread gibt, tritt selbst am Ende der Warteschlange ein und wird dann ausgesetzt und wartet auf LATCH_SH.

Die Prüfung auf wartende Threads wird durchgeführt, um Fairness gegenüber einem Thread zu gewährleisten, der auf den Latch im EX-Modus wartet. Es muss nur auf Threads warten, die das Latch im SH-Modus halten, der das Latch erworben hat, bevor es mit dem Warten begann. Ohne diese Überprüfung kann ein Informatikbegriff namens „Hunger“ auftreten, wenn ein konstanter Strom von Threads, die den Latch im SH-Modus erwerben, verhindert, dass der Thread im EX-Modus jemals in der Lage ist, den Latch zu erwerben.

Einen Riegel lösen

Wenn der Thread den Latch im EX-Modus hält, setzt er den Status zurück, der anzeigt, dass der Latch im EX-Modus gehalten wird, und prüft dann, ob es wartende Threads gibt.

Wenn der Thread den Latch im SH-Modus hält, verringert er die Anzahl der SH-Modus-Threads. Wenn der Zählwert jetzt nicht Null ist, wird der Freigabefaden mit dem Latch durchgeführt. Wenn der Zählwert jetzt Null ist, setzt es den Status zurück, der anzeigt, dass der Latch im SH-Modus gehalten wird, und prüft dann, ob es irgendwelche wartenden Threads gibt.

Wenn keine Threads warten, wird der Thread mit dem Latch freigegeben.

Wenn der Kopf der Warteschlange auf den EX-Modus wartet, macht der freigebende Thread Folgendes:

  • Stellt den Status ein, um anzuzeigen, dass der Latch im EX-Modus gehalten wird
  • Entfernt den wartenden Thread aus dem Kopf der Warteschlange und legt ihn als Besitzer des Latches fest
  • Signalisiert dem wartenden Thread, dass er der Eigentümer ist und jetzt ausgeführt werden kann (konzeptionell durch Verschieben des wartenden Threads von der Warteliste auf seinem Scheduler in die lauffähige Warteschlange auf dem Scheduler)
  • Und fertig ist der Riegel

Wenn der Kopf der Warteschlange im SH-Modus wartet (was nur der Fall sein kann, wenn der freigebende Thread im EX-Modus war), macht der freigebende Thread Folgendes:

  • Setzt den Status, um anzuzeigen, dass der Latch im SH-Modus gehalten wird
  • Für alle Threads in der Warteschlange, die auf den SH-Modus warten
    • Entfernt den wartenden Thread aus dem Kopf der Warteschlange
    • Inkrementiert die Anzahl der Threads, die den Latch halten
    • Signalisiert dem wartenden Thread, dass er Eigentümer ist und nun ausgeführt werden kann
  • Und fertig ist der Riegel

Wie können Latches ein Streitpunkt sein?

Im Gegensatz zu Sperren werden Latches im Allgemeinen nur für die Dauer des Lese- oder Änderungsvorgangs gehalten, sodass sie ziemlich leichtgewichtig sind, aber aufgrund der Inkompatibilität von SH und EX können sie ein ebenso großer Streitpunkt sein wie Sperren. Dies kann passieren, wenn viele Threads alle versuchen, einen Latch im EX-Modus zu erwerben (nur einer auf einmal) oder wenn viele Threads versuchen, einen Latch im SH-Modus zu erwerben, und ein anderer Thread den Latch im EX-Modus hält.

Zusammenfassung

Je mehr Threads im System um einen „Hot“-Latch kämpfen, desto größer ist die Konkurrenz und desto negativer wird die Auswirkung auf den Workload-Durchsatz sein. Sie haben wahrscheinlich schon von bekannten Latch-Konfliktproblemen gehört, zum Beispiel um tempdb-Zuweisungs-Bitmaps, aber Konflikte können auch bei Nicht-Seiten-Latches auftreten.

Jetzt habe ich Ihnen genügend Hintergrundinformationen gegeben, um Latches und ihre Funktionsweise zu verstehen. In den nächsten Artikeln werde ich einige reale Probleme mit Latch-Konflikten außerhalb von Seiten untersuchen und erklären, wie Sie sie verhindern oder umgehen können.