Heim > Datenbank > MySQL-Tutorial > Beispielanalyse zur Fehlerbehebung bei MySQL-Deadlocks

Beispielanalyse zur Fehlerbehebung bei MySQL-Deadlocks

WBOY
Freigeben: 2023-05-29 12:22:06
nach vorne
1335 Leute haben es durchsucht

Das Problem tritt auf

Eines Nachmittags alarmierte das System plötzlich und löste eine Ausnahme aus:

Bei näherer Betrachtung schien es sich um eine Transaktions-Rollback-Ausnahme zu handeln. Es stellte sich heraus, dass es sich um ein Deadlock-Problem handelte. Da ich immer noch ein gewisses Verständnis für MySQL-Sperren habe, begann ich, dieses Problem proaktiv zu untersuchen .

Suchen Sie zunächst in der Datenbank nach Innodb Status. Die letzten Deadlock-Informationen werden in Innodb Status aufgezeichnet ENGINE INNODB STATUS ANZEIGEN

Die Deadlock-Informationen lauten wie folgt und die SQL-Informationen wurden einfach verarbeitet:

​------------------------

LETZTER ERKANNTER DEADLOCK

​------------------------

22.02.2019 15:10:56 0x7eec2f468700

*** (1) TRANSAKTION:

TRANSAKTION 2660206487, AKTIV 0 Sek. Startindex-Lesevorgang

 MySQL-Tabellen verwendet 1, gesperrt 1

LOCK WAIT 2 Sperrstruktur(en), Heap-Größe 1136, 1 Zeilensperre(n)

MySQL-Thread-ID 31261312, Betriebssystem-Thread-Handle 139554322093824, Abfrage-ID 11624975750 10.23.134.92 erp_crm__6f73 Aktualisierung

/*id:3637ba36*/UPDATEmieter_config SET

​open_card_point = 0

​wobeimieter_id = 123

*** (1) WARTEN AUF DIE GEWÄHRUNG DIESER SPERRE:

RECORD LOCKS Space-ID 1322 Seitennummer 534 n Bits 960 Index uidx_tenant der Tabelle ——erp_crm_member_plan——. ——tenant_config—— trx id 2660206487 lock_mode X sperrt rec, aber kein Gap Waiting

*** (2) TRANSAKTION:

TRANSAKTION 2660206486, AKTIV 0 Sek. Startindex-Lesevorgang

 MySQL-Tabellen verwendet 1, gesperrt 1

​3 Sperrstruktur(en), Heap-Größe 1136, 2 Zeilensperre(n)

MySQL-Thread-ID 31261311, Betriebssystem-Thread-Handle 139552870532864, Abfrage-ID 11624975758 10.23.134.92 erp_crm__6f73 Aktualisierung

/*id:3637ba36*/UPDATEmieter_config SET

​open_card_point = 0

​wobeimieter_id = 123

*** (2) HÄLT DAS SCHLOSS(E):

RECORD LOCKS Space-ID 1322 Seitennummer 534 n Bits 960 Index uidx_tenant der Tabelle ——erp_crm_member_plan——. ——tenant_config—— trx id 2660206486 Sperrmodus S

*** (2) WARTEN AUF DIE GEWÄHRUNG DIESER SPERRE:

RECORD LOCKS Space-ID 1322 Seitennummer 534 n Bits 960 Index uidx_tenant der Tabelle ——erp_crm_member_plan—–. ——tenant_config—— trx id 2660206486 lock_mode X sperrt rec, aber kein Gap Waiting

*** WIR ROLLEN TRANSAKTION (1) ZURÜCK.

​----------------

Lassen Sie mich dieses Deadlock-Protokoll kurz analysieren und erklären. Wenn Transaktion 1 die Update-Anweisung ausführt, muss sie den uidx_tenant-Index abrufen und dann die X-Sperre (Zeilensperre) für die Where-Bedingung ausführen uidx_tenant. Um die X-Sperre (Zeilensperre) zu erhalten, kam es zu einem Deadlock und Transaktion 1 wurde zurückgesetzt. Ich war damals sehr verwirrt und erinnerte mich an die notwendigen Bedingungen für das Auftreten eines Deadlocks:

Sich gegenseitig ausschließend.

Bedingungen anfordern und zurückhalten.

Kein Entzug von Bedingungen.

Wartezyklus. Aus dem Protokoll ist ersichtlich, dass Transaktion 1 und Transaktion 2 beide um die Zeilensperre derselben Zeile konkurrieren. Dies unterscheidet sich ein wenig vom vorherigen zyklischen Wettbewerb um Sperren, egal wie man es betrachtet die zirkuläre Wartebedingung. Nachdem ich von Kollegen daran erinnert wurde, kann das Problem nur anhand des Geschäftscodes und der Geschäftsprotokolle untersucht werden, da das Deadlock-Protokoll nicht untersucht werden kann. Die Logik dieses Codes ist wie folgt:

public int saveTenantConfig(PoiContext poiContext, TenantConfigDOmieterConfig) {

Versuchen Sie es mit {

​returnmieterConfigMapper.saveTenantConfig(poiContext.getTenantId(), poiContext.getPoiId(),mieterConfig);

} Catch (DuplicateKeyException e) {

​LOGGER.warn("[saveTenantConfig] Primärschlüsselkonflikt, aktualisieren Sie den Datensatz. context:{}, config:{}", poiContext,mieterConfig);

​returnmieterConfigMapper.updateTenantConfig(poiContext.getTenantId(),mieterConfig);

}

}

Die Bedeutung dieses Codes besteht darin, eine Konfigurationsdatei zu speichern, die aktualisiert wird. Natürlich ist die Schreibweise hier nicht sehr standardisiert, aber sie kann tatsächlich verwendet werden in …

einfügen zur Aktualisierung des Duplikatschlüssels

Der gleiche Effekt kann erzielt werden, aber selbst wenn dies verwendet wird, kommt es tatsächlich zu einem Deadlock. Nachdem ich den Code gelesen hatte, schickte mir mein Kollege das damalige Geschäftsprotokoll,

Sie können sehen, dass drei Protokolle gleichzeitig aufgetreten sind, was darauf hinweist, dass ein eindeutiger Indexkonflikt aufgetreten ist und die aktualisierte Anweisung eingegeben wurde und dann ein Deadlock aufgetreten ist. An diesem Punkt scheint die Antwort endlich etwas klarer zu sein.

Schauen wir uns zu diesem Zeitpunkt unsere Tabellenstruktur wie folgt an (vereinfacht):

TABELLE ERSTELLEN ——tenant_config——

​——id—— bigint(21) NOT NULL AUTO_INCREMENT,

——tenant_id—— int (11) NICHT NULL,

——open_card_point—— int (11) DEFAULT NULL,

​PRIMÄRSCHLÜSSEL (——id——),

​EINZIGARTIGER SCHLÜSSEL ——uidx_tenant—— (——tenant_id——)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT

Unsere „tenant_id“ wird als eindeutiger Index verwendet, und unsere Einfüge- und Aktualisierungsbedingungen basieren alle auf dem eindeutigen Index.

AKTUALISIEREN Sie den Tenant_config SET

​open_card_point = 0

​wobeimieter_id = 123

An diesem Punkt bin ich der Meinung, dass das Sperren des eindeutigen Index beim Einfügen damit zusammenhängt. Als Nächstes werden wir im nächsten Schritt eine eingehende Analyse durchführen.

Eingehende Analyse

Oben haben wir gesagt, dass drei Transaktionen in die Aktualisierungsanweisung eingehen. Um die Erklärung zu vereinfachen, benötigen wir nur zwei Transaktionen, um die Aktualisierungsanweisung gleichzeitig einzugeben. Die folgende Tabelle zeigt unseren gesamten Ereignisprozess:

Tipp: Die S-Sperre ist eine gemeinsame Sperre und die X-Sperre eine gegenseitige Ausschlusssperre. Im Allgemeinen schließen sich X-Sperren, S-Sperren und X-Sperren gegenseitig aus, S-Sperren und S-Sperren schließen sich jedoch nicht gegenseitig aus.

Aus dem obigen Prozess sehen wir, dass der Schlüssel zu diesem Deadlock darin besteht, die S-Sperre zu erwerben. Warum müssen wir die S-Sperre beim erneuten Einfügen erwerben? Weil wir einen eindeutigen Index erkennen müssen? Wenn Sie unter der RR-Isolationsstufe lesen möchten, handelt es sich um den aktuellen Lesevorgang, sodass Sie tatsächlich eine S-Sperre hinzufügen müssen. Hier wird festgestellt, dass der eindeutige Schlüssel bereits vorhanden ist. Zu diesem Zeitpunkt wird die Ausführung der Aktualisierung durch die S-Sperren der beiden Transaktionen blockiert, wodurch die obige Schleifenwartebedingung entsteht.

Tipps: In MVCC besteht der Unterschied zwischen aktuellem Lesevorgang und Snapshot-Lesevorgang: Der aktuelle Lesevorgang muss jedes Mal gesperrt werden (Sie können eine gemeinsame Sperre oder eine Mutex-Sperre verwenden), um die neuesten Daten zu erhalten, während der Snapshot-Lesevorgang die zu diesem Zeitpunkt gestartete Transaktion liest. Der Snapshot wurde durch Undo-Log implementiert.

Dies ist der Grund für den gesamten Deadlock. Eine andere Situation, in der ein solcher Deadlock auftreten kann, besteht darin, dass drei Einfügevorgänge gleichzeitig ausgeführt werden. Wenn die zuerst eingefügte Transaktion am Ende zurückgesetzt wird, passiert dies auch bei den anderen beiden Transaktionen.

Lösung

Das Kernproblem besteht hier darin, die S-Sperre loszuwerden. Hier sind drei Lösungen als Referenz:

Reduzieren Sie die RR-Isolationsstufe auf die RC-Isolationsstufe. Hier verwendet die RC-Isolationsstufe das Snapshot-Lesen, sodass keine S-Sperre hinzugefügt wird.

Beim erneuten Einfügen verwenden Sie „select *“ für „Update“, um die X-Sperre hinzuzufügen, sodass die S-Sperre nicht hinzugefügt wird.

Sie können verteilte Sperren im Voraus hinzufügen, Sie können Redis oder ZK usw. verwenden. Informationen zu verteilten Sperren finden Sie in diesem Artikel von mir. Lassen Sie uns über verteilte Sperren sprechen

Die erste Methode ist nicht sehr realistisch, da die Isolationsstufe nicht einfach geändert werden kann. Die dritte Methode ist problematischer. Also haben wir uns letztendlich für die zweite Methode entschieden.

Das obige ist der detaillierte Inhalt vonBeispielanalyse zur Fehlerbehebung bei MySQL-Deadlocks. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage