Die Einrichtung der Replikation in MySQL ist einfach, aber die Verwaltung in der Produktion war noch nie eine leichte Aufgabe. Selbst mit der neueren automatischen GTID-Positionierung kann es immer noch schief gehen, wenn Sie nicht wissen, was Sie tun. Nach dem Einrichten der Replikation können alle möglichen Dinge schief gehen. Fehler können leicht gemacht werden und können ein katastrophales Ende für Ihre Daten haben.
Dieser Beitrag wird einige der häufigsten Fehler hervorheben, die bei der MySQL-Replikation gemacht werden, und wie Sie sie verhindern können.
Replikation einrichten
Beim Einrichten der MySQL-Replikation müssen Sie die Slave-Knoten mit dem Datensatz des Masters vorbereiten. Mit Lösungen wie dem Galera-Cluster wird dies automatisch für Sie mit der Methode Ihrer Wahl erledigt. Für die MySQL-Replikation müssen Sie dies selbst tun, also nehmen Sie natürlich Ihr Standard-Backup-Tool.
Für MySQL gibt es eine große Auswahl an Backup-Tools, aber das am häufigsten verwendete ist mysqldump. Mysqldump gibt ein logisches Backup des Datensatzes Ihres Masters aus. Das bedeutet, dass die Kopie der Daten keine binäre Kopie sein wird, sondern eine große Datei, die Abfragen enthält, um Ihren Datensatz neu zu erstellen. In den meisten Fällen sollte Ihnen dies eine (nahezu) identische Kopie Ihrer Daten liefern, aber es gibt Fälle, in denen dies nicht der Fall ist, da der Dump auf Objektbasis erfolgt. Das bedeutet, dass Ihr Datensatz nicht mit dem auf dem Master identisch ist, noch bevor Sie mit der Datenreplikation beginnen.
Es gibt ein paar Optimierungen, die Sie vornehmen können, um mysqldump zuverlässiger zu machen, wie dump als einzelne Transaktion, und vergessen Sie auch nicht, Routinen und Trigger einzufügen:
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > dumpfile.sql
Eine bewährte Vorgehensweise besteht darin, zu überprüfen, ob Ihr Slave-Knoten zu 100 % identisch ist, indem Sie nach dem Einrichten der Replikation pt-table-checksum verwenden:
pt-table-checksum --replicate=test.checksums --ignore-databases mysql h=localhost,u=user,p=pass
Dieses Tool berechnet eine Prüfsumme für jede Tabelle auf dem Master, repliziert den Befehl an den Slave und der Slave-Knoten führt dann dieselbe Prüfsummenoperation durch. Wenn eine der Tabellen nicht gleich ist, sollte dies in der Prüfsummentabelle deutlich sichtbar sein.
Verwendung der falschen Replikationsmethode
Die Standard-Replikationsmethode von MySQL war die sogenannte Statement-basierte Replikation. Diese Methode ist genau das, was sie ist:ein Replikationsstrom jeder Anweisung, die auf dem Master ausgeführt wird, der auf dem Slave-Knoten wiedergegeben wird. Da MySQL selbst multithreaded ist, seine (herkömmliche) Replikation jedoch nicht, ist die Reihenfolge der Anweisungen im Replikationsstrom möglicherweise nicht 100 % gleich. Auch die Wiedergabe einer Anweisung kann zu unterschiedlichen Ergebnissen führen, wenn sie nicht genau zur selben Zeit ausgeführt wird.
Dies kann aufgrund von Datendrift zu unterschiedlichen Datensätzen zwischen Master und Slave führen. Dies war viele Jahre lang kein Problem, da nicht viele MySQL mit vielen gleichzeitigen Threads ausführten, aber mit modernen Multi-CPU-Architekturen ist dies bei einer normalen täglichen Arbeitslast tatsächlich sehr wahrscheinlich geworden.
Die Antwort von MySQL war die sogenannte zeilenbasierte Replikation. Die zeilenbasierte Replikation repliziert die Daten wann immer möglich, verwendet aber in einigen Ausnahmefällen immer noch Anweisungen. Ein gutes Beispiel wäre die DLL-Änderung einer Tabelle, bei der die Replikation dann jede Zeile in der Tabelle durch Replikation kopieren müsste. Da dies ineffizient ist, wird eine solche Aussage auf traditionelle Weise repliziert. Wenn die zeilenbasierte Replikation eine Datendrift erkennt, stoppt sie den Slave-Thread, um Schlimmeres zu verhindern.
Dann gibt es eine Methode zwischen diesen beiden:Replikation im gemischten Modus. Diese Art der Replikation repliziert immer Anweisungen, außer wenn die Abfrage die UUID()-Funktion, Trigger, gespeicherte Prozeduren, UDFs und einige andere Ausnahmen enthält. Der gemischte Modus löst das Problem der Datendrift nicht und sollte zusammen mit der anweisungsbasierten Replikation vermieden werden.
Zirkuläre Replikation
Das Ausführen einer MySQL-Replikation mit Multi-Master ist häufig erforderlich, wenn Sie über eine Umgebung mit mehreren Rechenzentren verfügen. Da die Anwendung nicht darauf warten kann, dass der Master im anderen Rechenzentrum Ihren Schreibvorgang bestätigt, wird ein lokaler Master bevorzugt. Normalerweise wird der Autoinkrement-Offset verwendet, um Datenkollisionen zwischen den Mastern zu verhindern. Es ist eine allgemein akzeptierte Lösung, dass zwei Master auf diese Weise gegenseitig Schreibvorgänge ausführen.
MySQL Master-Master-ReplikationWenn Sie jedoch in mehreren Rechenzentren in dieselbe Datenbank schreiben müssen, haben Sie am Ende mehrere Master, die ihre Daten ineinander schreiben müssen. Vor MySQL 5.7.6 gab es keine Methode, um eine Mesh-Replikation durchzuführen, daher wäre die Alternative, stattdessen eine Ringreplikation zu verwenden.
Topologie der MySQL-RingreplikationDie Ringreplikation in MySQL ist aus folgenden Gründen problematisch:Latenz, Hochverfügbarkeit und Datendrift. Wenn Sie einige Daten auf Server A schreiben, würde es drei Sprünge dauern, bis sie auf Server D landen (über Server B und C). Da die (herkömmliche) MySQL-Replikation Single-Threaded ist, kann jede lange laufende Abfrage in der Replikation den gesamten Ring blockieren. Auch wenn einer der Server ausfallen würde, würde der Ring unterbrochen, und derzeit gibt es keine Failover-Software, die Ringstrukturen reparieren kann. Dann kann es zu einer Datendrift kommen, wenn Daten auf Server A geschrieben und gleichzeitig auf Server C oder D geändert werden.
Broken-Ring-ReplikationIm Allgemeinen passt die zirkuläre Replikation nicht gut zu MySQL und sollte um jeden Preis vermieden werden. Galera wäre eine gute Alternative für Schreibvorgänge in mehreren Rechenzentren, da es unter Berücksichtigung dessen entwickelt wurde.
Verzögern Ihrer Replikation durch große Updates
Oft führen verschiedene Housekeeping-Batch-Jobs verschiedene Aufgaben aus, die von der Bereinigung alter Daten bis zur Berechnung des Durchschnitts von „Likes“ aus einer anderen Quelle reichen. Das bedeutet, dass ein Job in festgelegten Intervallen viel Datenbankaktivität erzeugt und höchstwahrscheinlich viele Daten in die Datenbank zurückschreibt. Dies bedeutet natürlich, dass die Aktivität innerhalb des Replikationsstroms gleichermaßen zunimmt.
Die anweisungsbasierte Replikation repliziert die genauen Abfragen, die in den Batch-Jobs verwendet werden. Wenn also die Verarbeitung der Abfrage auf dem Master eine halbe Stunde dauerte, wird der Slave-Thread für mindestens die gleiche Zeit angehalten. Dies bedeutet, dass keine anderen Daten repliziert werden können und die Slave-Knoten beginnen, hinter dem Master zurückzubleiben. Wenn dies den Schwellenwert Ihres Failover-Tools oder Proxys überschreitet, werden diese Slave-Knoten möglicherweise von den verfügbaren Knoten im Cluster gelöscht. Wenn Sie die anweisungsbasierte Replikation verwenden, können Sie dies verhindern, indem Sie die Daten für Ihren Job in kleineren Stapeln verarbeiten.
Jetzt denken Sie vielleicht, dass die zeilenbasierte Replikation davon nicht betroffen ist, da sie die Zeileninformationen anstelle der Abfrage repliziert. Dies trifft teilweise zu, da bei DDL-Änderungen die Replikation wieder auf das anweisungsbasierte Format zurückkehrt. Auch eine große Anzahl von CRUD-Vorgängen wirkt sich auf den Replikationsstrom aus:In den meisten Fällen handelt es sich immer noch um einen Vorgang mit einem einzigen Thread, und daher wartet jede Transaktion darauf, dass die vorherige über die Replikation wiederholt wird. Das bedeutet, dass bei hoher Gleichzeitigkeit auf dem Master der Slave aufgrund der Transaktionsüberlastung während der Replikation ins Stocken geraten kann.
Um dies zu umgehen, bieten sowohl MariaDB als auch MySQL parallele Replikation an. Die Implementierung kann je nach Anbieter und Version unterschiedlich sein. MySQL 5.6 bietet parallele Replikation, solange die Abfragen nach Schema getrennt sind. MariaDB 10.0 und MySQL 5.7 können beide die parallele Replikation über Schemas hinweg handhaben, haben aber andere Grenzen. Das Ausführen von Abfragen über parallele Slave-Threads kann Ihren Replikationsstrom beschleunigen, wenn Sie viel schreiben. Wenn dies jedoch nicht der Fall ist, halten Sie sich am besten an die traditionelle Single-Thread-Replikation.
Schemaänderungen
Das Durchführen von Schemaänderungen in einer laufenden Produktionsumgebung ist immer mühsam. Dies hat damit zu tun, dass eine DDL-Änderung eine Tabelle meistens sperrt und diese Sperre erst wieder freigibt, wenn die DDL-Änderung angewendet wurde. Es wird sogar noch schlimmer, wenn Sie anfangen, diese DDL-Änderungen durch die MySQL-Replikation zu replizieren, wo es zusätzlich den Replikationsstrom blockiert.
Eine häufig verwendete Problemumgehung besteht darin, die Schemaänderung zuerst auf die Slave-Knoten anzuwenden. Für die anweisungsbasierte Replikation funktioniert dies gut, aber für die zeilenbasierte Replikation kann dies bis zu einem gewissen Grad funktionieren. Bei der zeilenbasierten Replikation können am Ende der Tabelle zusätzliche Spalten vorhanden sein. Solange die ersten Spalten geschrieben werden können, ist dies in Ordnung. Wenden Sie zuerst die Änderung auf alle Slaves an, führen Sie dann ein Failover auf einen der Slaves durch und wenden Sie dann die Änderung auf den Master an und hängen Sie diesen als Slave an. Wenn Ihre Änderung das Einfügen einer Spalte in der Mitte oder das Entfernen einer Spalte beinhaltet, funktioniert dies mit der zeilenbasierten Replikation.
Es gibt Tools, die Online-Schemaänderungen zuverlässiger durchführen können. Der Percona Online Schema Change (bekannt als pt-osc) erstellt eine Schattentabelle mit der neuen Tabellenstruktur, fügt neue Daten über Trigger ein und füllt Daten im Hintergrund auf. Sobald die neue Tabelle erstellt ist, wird einfach die alte gegen die neue Tabelle innerhalb einer Transaktion ausgetauscht. Dies funktioniert nicht in allen Fällen, insbesondere wenn Ihre vorhandene Tabelle bereits Trigger hat.
Eine Alternative ist das neue Tool Gh-ost von Github. Dieses Online-Schemaänderungstool erstellt zunächst eine Kopie Ihres vorhandenen Tabellenlayouts, ändert die Tabelle in das neue Layout und verbindet den Prozess dann als MySQL-Replik. Es verwendet den Replikationsstrom, um neue Zeilen zu finden, die in die ursprüngliche Tabelle eingefügt wurden, und füllt gleichzeitig die Tabelle auf. Sobald das Auffüllen abgeschlossen ist, wechseln die ursprüngliche und die neue Tabelle. Natürlich landen auch alle Operationen an der neuen Tabelle im Replikationsstrom, daher findet die Migration auf jeder Replik gleichzeitig statt.
Speichertabellen und Replikation
Wo wir gerade beim Thema DDLs sind, ein häufiges Problem ist die Erstellung von Speichertabellen. Speichertabellen sind nicht persistente Tabellen, ihre Tabellenstruktur bleibt erhalten, aber sie verlieren ihre Daten nach einem Neustart von MySQL. Wenn Sie eine neue Speichertabelle sowohl auf einem Master als auch auf einem Slave erstellen, haben beide eine leere Tabelle und dies funktioniert einwandfrei. Sobald einer von beiden neu gestartet wird, wird die Tabelle geleert und es treten Replikationsfehler auf.
Die zeilenbasierte Replikation bricht ab, sobald die Daten im Slave-Knoten andere Ergebnisse zurückgeben, und die anweisungsbasierte Replikation bricht ab, sobald sie versucht, bereits vorhandene Daten einzufügen. Für Speichertabellen ist dies ein häufiger Replikationsbrecher. Die Lösung ist einfach:Erstellen Sie einfach eine neue Kopie der Daten, ändern Sie die Engine auf InnoDB und es sollte jetzt replikationssicher sein.
Festlegen der read_only-Variable auf True
Wie wir bereits beschrieben haben, kann das Fehlen der gleichen Daten in den Slave-Knoten die Replikation unterbrechen. Oft wurde dies dadurch verursacht, dass etwas (oder jemand) die Daten auf dem Slave-Knoten geändert hat, aber nicht auf dem Master-Knoten. Sobald die Daten des Master-Knotens geändert werden, werden diese auf den Slave repliziert, wo er die Änderung nicht anwenden kann und dies dazu führt, dass die Replikation unterbrochen wird.
Dafür gibt es eine einfache Vorbeugung:Setzen Sie die read_only-Variable auf true. Dadurch wird es niemandem gestattet, Änderungen an den Daten vorzunehmen, mit Ausnahme der Replikations- und Root-Benutzer. Die meisten Failover-Manager setzen dieses Flag automatisch, um zu verhindern, dass Benutzer während des Failovers auf den verwendeten Master schreiben. Einige von ihnen behalten dies sogar nach dem Failover bei.
Dies überlässt es dem Root-Benutzer immer noch, eine fehlerhafte CRUD-Abfrage auf dem Slave-Knoten auszuführen. Um dies zu verhindern, gibt es seit MySQL 5.7.8 eine super_read_only-Variable, die sogar den Root-Benutzer daran hindert, Daten zu aktualisieren.
GTID aktivieren
Bei der MySQL-Replikation ist es wichtig, den Slave von der richtigen Position in den Binärlogs zu starten. Das Erhalten dieser Position kann erfolgen, wenn Sie ein Backup erstellen (xtrabackup und mysqldump unterstützen dies) oder wenn Sie aufgehört haben, auf einem Knoten zu arbeiten, von dem Sie eine Kopie erstellen. Das Starten der Replikation mit dem Befehl CHANGE MASTER TO würde wie folgt aussehen:
mysql> CHANGE MASTER TO MASTER_HOST='x.x.x.x',MASTER_USER='replication_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='master-bin.0001', MASTER_LOG_POS= 04;
Die Replikation an der falschen Stelle zu starten, kann fatale Folgen haben:Daten können doppelt geschrieben oder nicht aktualisiert werden. Dies verursacht eine Datendrift zwischen dem Master- und dem Slave-Knoten.
Auch beim Failover eines Masters auf einen Slave muss die richtige Position gefunden und der Master auf den entsprechenden Host geändert werden. MySQL behält die Binärlogs und Positionen von seinem Master nicht bei, sondern erstellt seine eigenen Binärlogs und Positionen. Für die Neuausrichtung eines Slave-Knotens auf den neuen Master könnte dies zu einem ernsthaften Problem werden:Die genaue Position des Masters beim Failover muss auf dem neuen Master gefunden werden, und dann können alle Slaves neu ausgerichtet werden.
Um dieses Problem zu lösen, wurde der Global Transaction Identifier (GTID) sowohl von Oracle als auch von MariaDB implementiert. GTIDs ermöglichen die automatische Ausrichtung von Slaves, und sowohl in MySQL als auch in MariaDB findet der Server selbst heraus, was die richtige Position ist. Allerdings haben beide die GTID auf unterschiedliche Weise implementiert und sind daher nicht kompatibel. Wenn Sie eine Replikation von einem zum anderen einrichten müssen, sollte die Replikation mit herkömmlicher binärer Log-Positionierung eingerichtet werden. Außerdem sollte Ihre Failover-Software darauf hingewiesen werden, keine GTIDs zu verwenden.
Schlussfolgerung
Wir hoffen, Ihnen genügend Tipps gegeben zu haben, um Ärger zu vermeiden. Dies sind alles gängige Praktiken der MySQL-Experten. Sie mussten es auf die harte Tour lernen und mit diesen Tipps sorgen wir dafür, dass Sie es nicht müssen.
Wir haben einige zusätzliche Whitepaper, die nützlich sein könnten, wenn Sie mehr über die MySQL-Replikation lesen möchten.
Zugehörige Whitepaper MySQL Replication BlueprintDas Whitepaper „MySQL Replication Blueprint“ umfasst alle Aspekte einer Replikationstopologie mit den Vor- und Nachteilen der Bereitstellung, Einrichtung der Replikation, Überwachung, Upgrades, Durchführung von Sicherungen und Verwaltung der Hochverfügbarkeit mithilfe von Proxys.MySQL Replication for High Availability herunterladenDieses Tutorial enthält Informationen über die MySQL-Replikation, mit Informationen zu den neuesten Funktionen, die in 5.6 und 5.7 eingeführt wurden. Es gibt auch einen praktischeren, praktischen Abschnitt zur schnellen Bereitstellung und Verwaltung eines Replikations-Setups mit ClusterControl.Download