Eine vollständige Aufzeichnung eines Mysql-Deadlock-Fehlerbehebungsprozesses

Eine vollständige Aufzeichnung eines Mysql-Deadlock-Fehlerbehebungsprozesses

Vorwort

Die Datenbank-Deadlocks, die ich zuvor erlebt habe, waren alle auf eine inkonsistente Sperrreihenfolge während der Stapelaktualisierungen zurückzuführen, aber letzte Woche bin ich auf einen Deadlock gestoßen, der sehr schwer zu verstehen war. Ich habe diese Gelegenheit genutzt, um mir mein Wissen über MySQL-Deadlocks und häufige Deadlock-Szenarien erneut anzueignen. Nach umfangreichen Recherchen und Diskussionen mit Kollegen habe ich schließlich die Ursache des Deadlock-Problems herausgefunden und viel daraus gelernt. Obwohl wir Backend-Programmierer sind, müssen wir den sperrenbezogenen Quellcode nicht so gründlich analysieren wie DBAs. Wenn wir jedoch die grundlegenden Methoden zur Fehlerbehebung bei Deadlocks beherrschen, wird dies für unsere tägliche Entwicklung von großem Nutzen sein.

PS: In diesem Artikel werden keine grundlegenden Kenntnisse über Deadlocks vermittelt. Informationen zum Sperrprinzip von MySQL finden Sie unter dem Link in den Referenzmaterialien dieses Artikels.

Ursachen für Deadlocks

Lassen Sie mich zunächst die Datenbank- und Tabellensituation vorstellen. Da es sich um echte Daten innerhalb des Unternehmens handelt, wird das Folgende simuliert und hat keinen Einfluss auf die spezifische Analyse.

Wir verwenden die MySQL-Datenbankversion 5.5, die Transaktionsisolationsebene ist standardmäßig RR (Repeatable-Read) und es wird die InnoDB-Engine verwendet. Angenommen, es gibt eine Testtabelle:

CREATE TABLE `test` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `a` int(11) unsigned DEFAULT NULL,
 Primärschlüssel (`id`),
 EINZIGARTIGER SCHLÜSSEL `a` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8;

Die Struktur der Tabelle ist sehr einfach, mit einem Primärschlüssel „id“ und einem weiteren eindeutigen Index „a“. Die Daten in der Tabelle sind wie folgt:

mysql> wähle * aus Test;
+----+------+
| Ich würde | ein |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 4 | 4 |
+----+------+
3 Zeilen im Satz (0,00 Sek.)

Die Vorgänge, die einen Deadlock verursachen, sind die folgenden:

Schritt Transaktion 1 Transaktion 2
1 beginnen
2 aus Test löschen, bei dem a = 2;
3 beginnen
4 Löschen aus Test, bei dem a = 2; (Transaktion 1 steckt fest)
5 Deadlock tritt auf: FEHLER 1213 (40001): Beim Versuch, eine Sperre zu erhalten, wurde ein Deadlock festgestellt. Versuchen Sie, die Transaktion neu zu starten. in Test (ID, a) Werte (10, 2) einfügen;

Anschließend können wir das Deadlock-Protokoll über SHOW ENGINE INNODB STATUS; ; anzeigen:

------------------------
Zuletzt erkannter Deadlock
------------------------
170219 13:31:31
*** (1) TRANSAKTION:
TRANSAKTION 2A8BD, AKTIV, 11 Sek. Start des Indexlesens
MySQL-Tabellen in Verwendung 1, gesperrt 1
LOCK WAIT 2 Sperrstrukturen, Heap-Größe 376, 1 Zeilensperre
MySQL-Thread-ID 448218, OS-Thread-Handle 0x2abe5fb5d700, Abfrage-ID 18923238 renjun.fangcloud.net 121.41.41.92 Root-Aktualisierung
aus dem Test löschen, bei dem a = 2
*** (1) WARTEN AUF DIE GEWÄHRUNG DIESER SPERRE:
RECORD LOCKS Bereichs-ID 0 Seitennummer 923 n Bits 80 Index „a“ der Tabelle „oauthdemo“. „test“ TRX-ID 2A8BD Sperrmodus X wartend
Datensatzsperre, Heap Nr. 3 PHYSIKALISCHER DATENSATZ: n_Felder 2; kompaktes Format; Infobits 32
 0: Länge 4; Hex 00000002; aufsteigend ;;
 1: Länge 4; Hex 00000002; aufsteigend ;;
*** (2) TRANSAKTION:
TRANSAKTION 2A8BC, AKTIV 18 Sek. Einfügen
MySQL-Tabellen in Verwendung 1, gesperrt 1
4 Sperrstruktur(en), Heapgröße 1248, 3 Zeilensperre(n), Undo-Logeinträge 2
MySQL-Thread-ID 448217, OS-Thread-Handle 0x2abe5fd65700, Abfrage-ID 18923239 renjun.fangcloud.net 121.41.41.92 Root-Update
in Test einfügen (id,a) Werte (10,2)
*** (2) HÄLT DAS SCHLOSS:
Datensatzsperren, Speicherplatz-ID 0, Seitennummer 923, n Bits 80, Index „a“ der Tabelle „oauthdemo“. „test“, TRX-ID 2A8BC, Sperrmodus X sperrt Datensatz, aber nicht Lücke
Datensatzsperre, Heap Nr. 3 PHYSIKALISCHER DATENSATZ: n_Felder 2; kompaktes Format; Infobits 32
 0: Länge 4; Hex 00000002; aufsteigend ;;
 1: Länge 4; Hex 00000002; aufsteigend ;;
*** (2) WARTEN AUF DIE GEWÄHRUNG DIESER SPERRE:
Datensatzsperren, Speicherplatz-ID 0, Seitennummer 923, n Bits 80, Index „a“ der Tabelle „oauthdemo“. „test“, TRX-ID 2A8BC, Sperrmodus S, wartend
Datensatzsperre, Heap Nr. 3 PHYSIKALISCHER DATENSATZ: n_Felder 2; kompaktes Format; Infobits 32
 0: Länge 4; Hex 00000002; aufsteigend ;;
 1: Länge 4; Hex 00000002; aufsteigend ;;
*** WIR MACHEN DIE TRANSAKTION ZURÜCK (1)

analysieren

Lesen des Deadlock-Protokolls

Wenn ein Deadlock auftritt, besteht der erste Schritt darin, das Deadlock-Protokoll zu lesen. Das Deadlock-Log ist in der Regel in zwei Teile gegliedert. Der erste Teil zeigt, auf welche Sperre Transaktion 1 wartet:

170219 13:31:31
*** (1) TRANSAKTION:
TRANSAKTION 2A8BD, AKTIV, 11 Sek. Start des Indexlesens
MySQL-Tabellen in Verwendung 1, gesperrt 1
LOCK WAIT 2 Sperrstrukturen, Heap-Größe 376, 1 Zeilensperre
MySQL-Thread-ID 448218, OS-Thread-Handle 0x2abe5fb5d700, Abfrage-ID 18923238 renjun.fangcloud.net 121.41.41.92 Root-Aktualisierung
aus dem Test löschen, bei dem a = 2
*** (1) WARTEN AUF DIE GEWÄHRUNG DIESER SPERRE:
RECORD LOCKS Bereichs-ID 0 Seitennummer 923 n Bits 80 Index „a“ der Tabelle „oauthdemo“. „test“ TRX-ID 2A8BD Sperrmodus X wartend
Datensatzsperre, Heap Nr. 3 PHYSIKALISCHER DATENSATZ: n_Felder 2; kompaktes Format; Infobits 32
 0: Länge 4; Hex 00000002; aufsteigend ;;
 1: Länge 4; Hex 00000002; aufsteigend ;;

Aus dem Protokoll können wir ersehen, dass Transaktion 1 derzeit delete from test where a = 2 ausführt. Diese Anweisung wendet eine X-Sperre auf den Index a an, daher wird lock_mode X waiting angezeigt.

In der unteren Hälfte des Protokolls werden dann die Sperren angezeigt, die Transaktion 2 derzeit hält und auf die sie wartet:

*** (2) TRANSAKTION:
TRANSAKTION 2A8BC, AKTIV 18 Sek. Einfügen
MySQL-Tabellen in Verwendung 1, gesperrt 1
4 Sperrstruktur(en), Heapgröße 1248, 3 Zeilensperre(n), Undo-Logeinträge 2
MySQL-Thread-ID 448217, OS-Thread-Handle 0x2abe5fd65700, Abfrage-ID 18923239 renjun.fangcloud.net 121.41.41.92 Root-Update
in Test einfügen (id,a) Werte (10,2)
*** (2) HÄLT DAS SCHLOSS:
Datensatzsperren, Speicherplatz-ID 0, Seitennummer 923, n Bits 80, Index „a“ der Tabelle „oauthdemo“. „test“, TRX-ID 2A8BC, Sperrmodus X sperrt Datensatz, aber nicht Lücke
Datensatzsperre, Heap Nr. 3 PHYSIKALISCHER DATENSATZ: n_Felder 2; kompaktes Format; Infobits 32
 0: Länge 4; Hex 00000002; aufsteigend ;;
 1: Länge 4; Hex 00000002; aufsteigend ;;
*** (2) WARTEN AUF DIE GEWÄHRUNG DIESER SPERRE:
Datensatzsperren, Speicherplatz-ID 0, Seitennummer 923, n Bits 80, Index „a“ der Tabelle „oauthdemo“. „test“, TRX-ID 2A8BC, Sperrmodus S, wartend
Datensatzsperre, Heap Nr. 3 PHYSIKALISCHER DATENSATZ: n_Felder 2; kompaktes Format; Infobits 32
 0: Länge 4; Hex 00000002; aufsteigend ;;
 1: Länge 4; Hex 00000002; aufsteigend ;;

Aus HOLDS THE LOCKS(S) im Protokoll können wir erkennen, dass Transaktion 2 eine X-Sperre auf Index a hält und es sich um eine Datensatzsperre handelt. Die Sperre wird durch die Löschanweisung erworben, die von Transaktion 2 in Schritt 2 ausgeführt wird. Da es sich um eine Gleichheitsabfrage handelt, die auf einem eindeutigen Index im RR-Isolationsmodus basiert (wobei a = 2), wird anstelle einer Next-Key-Sperre eine Datensatzsperre angefordert.

Aus WAITING FOR THIS LOCK TO BE GRANTED , bei der es sich um eine gemeinsam genutzte Sperre handelt. Die Sperre wird durch die Anweisung insert into test(id,a) values ​​(10,2) angewendet. Normalerweise gilt für die Einfügeanweisung eine exklusive Sperre, also eine X-Sperre, hier erscheint jedoch eine S-Sperre. Dies liegt daran, dass Feld a ein eindeutiger Index ist. Daher führt die Einfügeanweisung vor dem Einfügen eine Überprüfung duplicate key durch. Damit diese Überprüfung erfolgreich ist, muss eine S-Sperre beantragt werden, um zu verhindern, dass andere Transaktionen Feld a ändern.

Warum also versagt das S-Schloss? Dies bedeutet, dass Anträge auf Sperren desselben Feldes in die Warteschlange gestellt werden müssen. Vor der S-Sperre gibt es eine erfolglose X-Sperre, sodass die S-Sperre warten muss. Dadurch entsteht ein Wartezirkel und es kommt zu einem Deadlock.

Durch Lesen des Deadlock-Protokolls können wir deutlich erkennen, welche Art von zyklischem Warten durch die beiden Transaktionen verursacht wird. Nach weiterer Analyse können wir umgekehrt auf die Ursache des zyklischen Wartens schließen, d. h. auf die Ursache des Deadlocks.

Flussdiagramm zur Entstehung von Deadlocks

Um Ihnen zu helfen, die Ursachen von Deadlocks besser zu verstehen, erläutern wir den Prozess der Deadlock-Entstehung in Form einer Tabelle:

Schritt Transaktion 1 Transaktion 2
1 beginnen
2 Löschen aus Test, wobei a = 2; Die Ausführung ist erfolgreich. Transaktion 2 hält die X-Sperre unter a=2 und der Typ ist eine Datensatzsperre.
3 beginnen
4 Löschen aus Test, wobei a = 2; Transaktion 1 möchte unter a=2 eine X-Sperre beantragen, da aber Transaktion 2 bereits eine X-Sperre beantragt hat und die beiden X-Sperren sich gegenseitig ausschließen, tritt die X-Sperranwendung in die Warteschlange für Sperranforderungen ein.
5 Es kommt zu einem Deadlock und Transaktion 1 hat ein geringeres Gewicht, sodass sie für ein Rollback ausgewählt wird (sie wird zum Opfer). insert into test(id, a) values(10, 2); Da ein Feld einen eindeutigen Index hat, ist eine S-Sperre erforderlich, um auf doppelte Schlüssel zu prüfen. Da der Wert von a inserted immer noch 2 ist, wird es nach der X-Sperre eingestuft. Die vorherige Anwendung der X-Sperre kann jedoch erst erfolgreich sein, nachdem Transaktion 2 festgeschrieben oder zurückgesetzt wurde. Dadurch entsteht eine zirkuläre Wartezeit, die einen Deadlock verursacht.

expandieren

Während der Fehlerbehebung beim Deadlock stellte ein Kollege fest, dass das obige Szenario einen weiteren Deadlock erzeugen würde, der nicht manuell reproduziert werden konnte und nur in einem Szenario mit hoher Parallelität reproduziert werden konnte.

Das diesem Deadlock entsprechende Protokoll wird hier nicht veröffentlicht. lock_mode X locks gap before rec insert intention waiting bevor auf die beabsichtigte Rec-Einfügung gewartet wird.

Wir verwenden dennoch eine Tabelle, um den Prozess der Deadlock-Generierung im Detail zu erklären:

Schritt Transaktion 1 Transaktion 2
1 beginnen
2 Löschen aus Test, wobei a = 2; Die Ausführung ist erfolgreich. Transaktion 2 hält die X-Sperre unter a=2 und der Typ ist eine Datensatzsperre.
3 beginnen
4 [Einfügungsphase 1] Füge in Test (ID, A) die Werte (10, 2) ein. Transaktion 2 beantragt ein S-Schloss, um den doppelten Schlüssel zu prüfen. Die Prüfung war erfolgreich.
5 Löschen aus Test, wobei a = 2; Transaktion 1 möchte unter a=2 eine X-Sperre beantragen, da aber Transaktion 2 bereits eine X-Sperre beantragt hat und die beiden X-Sperren sich gegenseitig ausschließen, tritt die X-Sperranwendung in die Warteschlange für Sperranforderungen ein.
6 Es kommt zu einem Deadlock und Transaktion 1 hat ein geringeres Gewicht, sodass sie für ein Rollback ausgewählt wird (sie wird zum Opfer). [Einfügephase 2] Einfügen in Test (ID, a) Werte (10, 2); Transaktion 2 beginnt mit dem Einfügen von Daten, und die S-Sperre wird auf die X-Sperre aktualisiert, wobei der Typ die Einfügeabsicht ist. In ähnlicher Weise gelangen X-Sperren in die Warteschlange, wodurch ein zirkulärer Wartezyklus entsteht und ein Deadlock verursacht wird.

Zusammenfassen

Bei der Fehlerbehebung bei Deadlocks müssen Sie zunächst das Szenario des zyklischen Wartens anhand des Deadlock-Protokolls analysieren, dann den Sperrtyp und die Sequenz anhand des von jeder aktuellen Transaktion ausgeführten SQL analysieren und umgekehrt ableiten, wie das zyklische Warten zustande kommt. Auf diese Weise können Sie die Ursache des Deadlocks finden.

Das ist alles für diesen Artikel. Ich hoffe, dass der Inhalt dieses Artikels Ihnen bei Ihrem Studium oder Ihrer Arbeit hilfreich sein kann. Die obige Analyse basiert auf Erfahrung. Ich hoffe, dass andere Freunde auf die Fehler und Mängel hinweisen können. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM.

Das könnte Sie auch interessieren:
  • Detaillierte Erklärung von Deadlock-Situationen in MySQL und wie man mit Deadlocks umgeht
  • Ursachen und Lösungen für einen Deadlock in der MySQL-Datenbank
  • So finden Sie die ID eines Deadlocks in einem MySQL-Thread
  • Analyse einer Deadlock-Instanz in einer MySQL-Datenbank
  • Analyse eines MySQL-Deadlock-Szenariobeispiels
  • Eine detaillierte Diskussion über MySQL-Deadlocks und -Logs
  • MySQL-Leistungsoptimierungs-Sharing (Sharding von Datenbanken und Tabellen)
  • MyBatis implementiert Mysql-Datenbank-Unterbibliotheks- und Untertabellenoperationen und -zusammenfassungen (empfohlen)
  • Zusammenfassung der Datenaufteilung in MySQL-Datenbanken: Unterbibliothek und Untertabelle
  • Detaillierte Erläuterung von MySQL-Deadlocks sowie Datenbank- und Tabellen-Sharding-Problemen

<<:  Tipps zur Verwendung des Top-Befehls in Linux

>>:  jQuery verwendet die Funktionen hide() und toggle(), um die Funktion zum Ausblenden der Kameramarkenanzeige zu realisieren

Artikel empfehlen

HTML-Grammatik-Enzyklopädie_HTML-Sprachgrammatik-Enzyklopädie (unbedingt lesen)

Datenträgerbezeichnung, Eigenschaftsname, Beschre...

Detaillierte Erklärung der InnoDB-Speicherdateien in MySQL

Physisch gesehen besteht eine InnoDB-Tabelle aus ...

Detaillierte Erklärung und Zusammenfassung der URL zur Datenbankverbindung

Detaillierte Erklärung und Zusammenfassung der UR...

Beispiel für den Import von Nginx-Protokollen in Elasticsearch

Die Nginx-Protokolle werden von Filebeat gesammel...

Analyse der Lösung für das Problem der gemeinsamen Nutzung von Nginx-Sitzungen

Dieser Artikel stellt hauptsächlich die Lösung fü...

So zeigen Sie in CocosCreator eine Textur an der Wischposition an

Inhaltsverzeichnis 1. Projektanforderungen 2. Dok...

Lösung für mehrere 302-Antworten im Nginx-Proxy (Nginx Follow 302)

Proxying mehrerer 302er mit proxy_intercept_error...

Detaillierte Erklärung des Unterschieds zwischen tinyint und int in MySQL

Frage: Was ist der Unterschied zwischen int(1) un...

Detaillierte Analyse des React Diff-Prinzips

Inhaltsverzeichnis Diffing-Algorithmus Schicht-fü...