MariaDB
 sql >> Datenbank >  >> RDS >> MariaDB

Umgang mit Replikationsproblemen von Nicht-GTID- zu GTID-MariaDB-Datenbankclustern

Wir sind kürzlich auf einen interessanten Kundensupport-Fall gestoßen, bei dem es um die Einrichtung einer MariaDB-Replikation ging. Wir haben viel Zeit damit verbracht, dieses Problem zu untersuchen, und dachten, dass es sich lohnen würde, es in diesem Blogbeitrag mit Ihnen zu teilen.

Umgebungsbeschreibung des Kunden

Das Problem war wie folgt:Ein alter (vor 10.x) MariaDB-Server wurde verwendet und es wurde versucht, Daten von ihm in eine neuere MariaDB-Replikationskonfiguration zu migrieren. Dies führte zu Problemen bei der Verwendung von Mariabackup zum Neuerstellen von Slaves im neuen Replikationscluster. Für die Zwecke der Tests haben wir dieses Verhalten in der folgenden Umgebung nachgebildet:

Die Daten wurden mit mysqldump von 5.5 auf 10.4 migriert:

mysqldump --single-transaction --master-data=2 --events --routines sbtest > /root/dump.sql

Dies ermöglichte uns, Master-Binärlog-Koordinaten und den konsistenten Dump zu sammeln. Als Ergebnis konnten wir den MariaDB 10.4-Master-Knoten bereitstellen und die Replikation zwischen dem alten 5.5-Master und dem neuen 10.4-Knoten einrichten. Der Datenverkehr lief noch auf 5.5-Knoten. Der 10.4-Master generierte GTIDs, da er Daten auf den 10.4-Slave replizieren musste. Bevor wir ins Detail gehen, werfen wir einen kurzen Blick darauf, wie GTID in MariaDB funktioniert.

MariaDB und GTID

Für den Anfang verwendet MariaDB ein anderes Format der GTID als Oracle MySQL. Es besteht aus drei Zahlen, die durch Bindestriche getrennt sind:

0 - 1 - 345

Das erste ist eine Replikationsdomäne, die es ermöglicht, dass die Multisource-Replikation richtig gehandhabt wird. Dies ist für unseren Fall nicht relevant, da sich alle Knoten in derselben Replikationsdomäne befinden. Die zweite Zahl ist die Server-ID des Knotens, der die GTID generiert hat. Die dritte ist die Sequenznummer - sie steigt monoton mit jedem in den Binärprotokollen gespeicherten Ereignis.

MariaDB verwendet mehrere Variablen, um die Informationen über GTIDs zu speichern, die auf einem bestimmten Knoten ausgeführt werden. Die interessantesten für uns sind:

Gtid_binlog_pos - laut Dokumentation ist diese Variable die GTID der letzten Ereignisgruppe, die in das Binärlog geschrieben wurde.

Gtid_slave_pos - laut Dokumentation enthält diese Systemvariable die GTID der letzten Transaktion, die von den Slave-Threads des Servers auf die Datenbank angewendet wurde.

Gtid_current_pos - laut Dokumentation enthält diese Systemvariable die GTID der letzten in die Datenbank übernommenen Transaktion. Wenn die server_id der entsprechenden GTID in gtid_binlog_pos gleich der eigenen server_id des Servers ist und die Sequenznummer höher ist als die entsprechende GTID in gtid_slave_pos, dann wird die GTID aus gtid_binlog_pos verwendet. Andernfalls wird die GTID von gtid_slave_pos für diese Domain verwendet.

Um es klarzustellen, speichert gtid_binlog_pos die GTID des letzten lokal ausgeführten Ereignisses. Gtid_slave_pos speichert die GTID des vom Slave-Thread ausgeführten Ereignisses und gtid_current_pos zeigt entweder den Wert von gtid_binlog_pos, wenn es die höchste Sequenznummer und eine Server-ID hat, oder gtid_slave_pos, wenn es die höchste Sequenz hat. Bitte denken Sie daran.

Ein Überblick über das Problem

Der Anfangszustand der relevanten Variablen ist auf 10.4 Master:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+----------+

| Variable_name           | Value |

+-------------------------+----------+

| gtid_binlog_pos         | 0-1001-1 |

| gtid_binlog_state       | 0-1001-1 |

| gtid_cleanup_batch_size | 64       |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+----------+

11 rows in set (0.001 sec)

Bitte beachten Sie gtid_slave_pos, was theoretisch keinen Sinn ergibt - es kam vom selben Knoten, aber über einen Slave-Thread. Dies könnte passieren, wenn Sie vorher einen Hauptschalter machen. Genau das haben wir getan – mit zwei 10.4-Knoten haben wir die Master vom Host mit der Server-ID 1001 auf den Host mit der Server-ID 1002 und dann zurück auf 1001 umgeschaltet.

Danach haben wir die Replikation von 5.5 auf 10.4 konfiguriert und so sah es aus:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+-------------------------+

| Variable_name           | Value |

+-------------------------+-------------------------+

| gtid_binlog_pos         | 0-55-117029 |

| gtid_binlog_state       | 0-1001-1537,0-55-117029 |

| gtid_cleanup_batch_size | 64                      |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+-------------------------+

11 rows in set (0.000 sec)

Wie Sie sehen können, wurden die von MariaDB 5.5 replizierten Ereignisse alle in der Variablen gtid_binlog_pos berücksichtigt:alle Ereignisse mit der Server-ID 55. Dies führt zu einem ernsthaften Problem. Wie Sie sich vielleicht erinnern, sollte gtid_binlog_pos Ereignisse enthalten, die lokal auf dem Host ausgeführt werden. Hier enthält es Ereignisse, die von einem anderen Server mit einer anderen Server-ID repliziert wurden.

Das macht die Sache heikel, wenn Sie den 10.4-Slave neu bauen wollen, hier ist der Grund. Mariabackup funktioniert genau wie Xtrabackup auf einfache Weise. Es kopiert die Dateien vom MariaDB-Server, scannt Redo-Protokolle und speichert alle eingehenden Transaktionen. Wenn die Dateien kopiert wurden, friert Mariabackup die Datenbank ein, indem es entweder FLUSH TABLES WITH READ LOCK oder Backup-Sperren verwendet, abhängig von der MariaDB-Version und der Verfügbarkeit der Backup-Sperren. Dann liest es die zuletzt ausgeführte GTID und speichert sie zusammen mit dem Backup. Dann wird die Sperre aufgehoben und die Sicherung abgeschlossen. Die im Backup gespeicherte GTID sollte als letzte ausgeführte GTID auf einem Knoten verwendet werden. Im Falle des Neuaufbaus von Slaves wird es als gtid_slave_pos abgelegt und dann verwendet, um die GTID-Replikation zu starten. Diese GTID wird aus gtid_current_pos übernommen, was durchaus Sinn macht – schließlich ist es die „GTID der letzten in die Datenbank übernommenen Transaktion“. Scharfsinnige Leser sehen das Problem bereits. Lassen Sie uns die Ausgabe der Variablen zeigen, wenn 10.4 vom 5.5-Master repliziert:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+-------------------------+

| Variable_name           | Value |

+-------------------------+-------------------------+

| gtid_binlog_pos         | 0-55-117029 |

| gtid_binlog_state       | 0-1001-1537,0-55-117029 |

| gtid_cleanup_batch_size | 64                      |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+-------------------------+

11 rows in set (0.000 sec)

Gtid_current_pos ist auf 0-1001-1 gesetzt. Dies ist definitiv nicht der richtige Zeitpunkt, es stammt aus gtid_slave_pos, während wir eine Reihe von Transaktionen haben, die danach aus 5.5 stammen. Das Problem ist, dass diese Transaktionen als gtid_binlog_pos gespeichert werden. Andererseits wird gtid_current_pos so berechnet, dass es eine lokale Server-ID für GTIDs in gitd_binlog_pos erfordert, bevor sie als gtid_current_pos verwendet werden können. In unserem Fall haben sie die Server-ID des 5.5-Knotens, sodass sie nicht richtig als Ereignisse behandelt werden, die auf dem 10.4-Master ausgeführt werden. Wenn Sie nach der Backup-Wiederherstellung den Slave gemäß dem im Backup gespeicherten GTID-Status einstellen würden, würde er am Ende alle Ereignisse erneut anwenden, die aus 5.5 stammen. Dies würde natürlich die Replikation unterbrechen.

Die Lösung

Eine Lösung für dieses Problem sind mehrere zusätzliche Schritte:

  1. Stoppen Sie die Replikation von 5.5 auf 10.4. Führen Sie STOP SLAVE auf 10.4-Master aus
  2. Führen Sie eine beliebige Transaktion auf 10.4 aus - CREATE SCHEMA IF NOT EXISTS Bugfix - dies wird die GTID-Situation wie folgt ändern:
MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+---------------------------+

| Variable_name           | Value   |

+-------------------------+---------------------------+

| gtid_binlog_pos         | 0-1001-117122   |

| gtid_binlog_state       | 0-55-117121,0-1001-117122 |

| gtid_cleanup_batch_size | 64                        |

| gtid_current_pos        | 0-1001-117122   |

| gtid_domain_id          | 0   |

| gtid_ignore_duplicates  | ON   |

| gtid_pos_auto_engines   |   |

| gtid_slave_pos          | 0-1001-1   |

| gtid_strict_mode        | ON   |

| wsrep_gtid_domain_id    | 0   |

| wsrep_gtid_mode         | OFF   |

+-------------------------+---------------------------+

11 rows in set (0.001 sec)

Die neueste GITD wurde lokal ausgeführt, also wurde sie als gtid_binlog_pos gespeichert. Da es die lokale Server-ID hat, wird es als gtid_current_pos ausgewählt. Jetzt können Sie ein Backup erstellen und es verwenden, um Slaves vom 10.4-Master neu zu erstellen. Sobald dies erledigt ist, starten Sie den Slave-Thread erneut.

MariaDB ist sich bewusst, dass diese Art von Fehler existiert, einer der relevanten Fehlerberichte, die wir gefunden haben, ist: https://jira.mariadb.org/browse/MDEV-10279 Leider gibt es bisher keine Lösung . Wir haben festgestellt, dass dieses Problem MariaDB bis Version 5.5 betrifft. Nicht-GTID-Ereignisse, die von MariaDB 10.0 stammen, werden in 10.4 korrekt als vom Slave-Thread kommend berücksichtigt und gtid_slave_pos wird ordnungsgemäß aktualisiert. MariaDB 5.5 ist ziemlich alt (obwohl es noch unterstützt wird), sodass Sie möglicherweise immer noch Setups sehen, die darauf ausgeführt werden, und versuchen, von 5.5 auf neuere, GTID-fähige MariaDB-Versionen zu migrieren. Was noch schlimmer ist, betrifft laut dem von uns gefundenen Fehlerbericht auch die Replikation von Nicht-MariaDB-Servern (einer der Kommentare erwähnt das Problem, das auf Percona Server 5.6 auftaucht) in MariaDB.

Trotzdem hoffen wir, dass Sie diesen Blogbeitrag nützlich fanden und hoffentlich nicht auf das gerade beschriebene Problem stoßen werden.