MySQL verteilen und sichern: Master und Slave

17.05.2005 von THOMAS WOELFER 
MySQL bietet viele Möglichkeiten zur Sicherung der Daten. Auch wenn man auf ein Backup nicht verzichten sollte: Ein Master-Slave-Setup, bei dem der Slave als Live-Kopie läuft, ist die praktischste aller Methoden.

Beim Master-Slave-Betrieb von MySQL kommen mindestens zwei Rechner zum Einsatz. Auf einem Rechner läuft eine normale MySQL-Datenbank, während der zweite und alle weiteren Rechner als Slave fungieren. Ein solches Sklaven-MySQL ist dabei mit dem Master-Server verbunden. Der Master führt Buch über alle stattfindenden Transaktionen, und der Slave führt anhand dieser Buchführung alle Transaktionen ebenfalls aus. Dabei geht es nur um Änderungen an der Datenbank: Befehle, die auf Inhalt oder Zustand der Datenbank keine Auswirkung haben, werden vom Slave nicht ausgewertet.

Das Resultat ist eine MySQL-Datenbank, die zusätzlich zum Master-Server über alle aktuellen Daten verfügt, und zwar so zeitnah, dass der Inhalt praktisch immer identisch mit dem der Master-Datenbank ist. Da aber nur Veränderungen an der Datenbasis mitgeführt werden, liegt die Last des Slave-Rechners fast bei null. Man kann diesen Rechner also für sekundäre Zwecke oder als Entlastung für den Master-Server verwenden.

Da sich bei MySQL beliebig viele Slaves einsetzen lassen, ist mit dem Master/Slave-Mechanismus auch ein einfaches Loadbalancing für den Server möglich: Änderungen werden nur über den Master-Server durchgeführt, CPU-intensive Queries werden hingegen auf mehrere Rechner verteilt.

Die Replikation

Die Einwege-Replikation bei MySQL basiert auf dem Binary-Log des Masters und steht seit Version 3.23.15 zur Verfügung. Ist das Binary-Log auf dem Master aktiviert, protokolliert dieser alle Queries, die zu Änderungen an der Datenbasis führen, in diesem Log. Jeder Eintrag im Binary-Log hat dabei eine eindeutige Positionskennung, also eine Art Hausnummer, mit der ein bestimmter Zustand im Master identifiziert werden kann.

Verbindet sich ein Slave mit dem Server, dann teilt dieser Slave dem Master im Zuge der Verbindung mit, an welcher Stelle er sich innerhalb des Binary-Logs befindet. Darauf reagiert der Master, indem er dem Slave alle Updates seit dieser Position mitteilt. Auf Basis dieser Information kann der Slave dann seine eigenen Daten auf den aktuellen Stand bringen. Sind Master und Slave auf dem gleichen Stand, so wartet der Slave auf weitere Updates und hält somit, solange er verbunden ist, immer die gleichen Daten vorrätig wie der Master.

Dies bringt einige interessante Implikationen mit sich: Es ist beispielsweise nicht notwendig, dass der Slave zu jedem Zeitpunkt mit dem Master verbunden bleibt. Trennt man die Verbindung, etwa um den Slave zu warten, so muss man die Verbindung nur wieder herstellen, um den Slave auf den neuesten Stand der Datenbasis zu bringen. Das ist nicht nur für einfache Wartungszwecke, sondern auch für aufwendige Operationen wie Komplett-Backups oder Betriebssystem-Updates optimal.

Replika als Backup

Ein "live" mitgeführter Slave-Rechner stellt parallel ein wertvolles Backup des Masters dar. Fällt dieser aus - etwa auf Grund eines Hardware-Defekts, liegt immer ein vollständig auf dem aktuellen Stand der Daten befindlicher Server vor, der mit wenigen Handgriffen die Aufgaben des Masters übernehmen kann: Ein MySQL-Slave ist somit stets auch ein vollwertiger MySQL-Server. Statt den Slave zum Master umzubauen, können Sie einfach einen neuen Server aufsetzen und diesen mit den Daten aus dem Slave bestücken. Letztlich kommt es ja nur darauf an, einen möglichst aktuellen Datenbestand vorzuhalten.

Das Live-Update des Slave ist jedoch nicht ohne Tücken: Da der Slave alle Änderungen am Server praktisch in Echtzeit mitführt, machen sich auch Fehler bei der Wartung des Masters direkt bemerkbar. Wird die Datenbasis auf dem Server durch ein fehlerhaftes SQL-Query irrtümlich gelöscht (etwa durch ein "delete from TableName"), dann sind die Daten anschließend auch auf dem Slave verschwunden. Es empfiehlt sich also nicht, ein Master/Slave-Setup als einzigen Backup-Mechanismus zu verwenden. Tut man dies doch, so ist einem Desaster Tür und Tor geöffnet.

Auch mehrere Slaves lösen dieses Problem nicht: Letztlich spielt es keine Rolle, auf wie vielen Systemen die Daten gleichzeitig gelöscht werden: Sind die Daten weg, dann sind sie weg. Sicherlich könnte man mehrere Slaves verwenden, die sich zeitversetzt mit dem Master verbinden und wieder getrennt werden: Ein echtes Backup sollten Sie trotzdem auf jeden Fall zur Verfügung haben.

Master/Slave aktivieren

Damit Sie die Replikation per Master/Slave einsetzen können, müssen Sie das Binary-Log auf dem Master aktivieren und den Slave-Rechner mit der Datenbasis ausstatten, die beim Master vorlag, unmittelbar bevor Sie dort das Binary-Log eingeschaltet haben.

Das ist eine logische Konsequenz aus der Tatsache, dass das Binary-Log einfach auf dem Slave abgespielt wird. Angenommen, der erste Eintrag im Binary-Log enthält den Befehl "delete from users where id=5". Dies würde fehlschlagen, wenn weder eine Tabelle namens users, noch ein Eintrag mit der ID 5 auf dem Slave vorliegt. Die Datenbasis und das Binary-Log müssen also zusammenpassen. Das bedeutet auch, dass Sie am besten eine Kopie der Datenbasis vor dem Einschalten des Binary-Log anlegen - und diese Kopie gut aufbewahren: Sie werden diese nämlich später benötigen, wenn Sie vielleicht einen dritten Rechner als Slave betreiben wollen. Es sei denn, Sie setzen den vorhandenen Slave später zurück und installieren diesen zusammen mit dem zweiten neu.

Am einfachsten gehen Sie dabei folgendermaßen vor:

Wann Sie danach den Slave einschalten, ist egal - er holt den Master ganz von selbst wieder ein. Zum Sichern und Kopieren der Daten vom Master auf den Slave gibt es verschiedene Ansätze, alle gängigen finden Sie in der Dokumentation zum Thema Backup auf der MySQL-Webseite erläutert. Daher schildern wir im Folgenden nur die beiden einfachsten Methoden in Kurzform.

Daten kopieren mit Mysqldump

Das Programm mysqldump kann eine komplette Datenbank von einem MySQL-Server auf die Festplatte schreiben. Man braucht dazu keinen Shell-Account auf dem Rechner mit dem MySQL-Server. Allerdings muss der Port für MySQL im freien Zugriff stehen, denn sonst kann sich mysqldump nicht mit dem Server verbinden. Der Aufruf von mysqldump lautet wie folgt:

bash> mysqldump [OPTIONEN] database [Tabellen]

[Tabellen] bedeutet in diesem Zusammenhang eine Auflistung der Tabellen, die gesichert werden sollen. Wenn Sie diese Angabe weglassen, dann schreibt mysqldump einfach alle Tabellen, das ist wohl der Normalfall, und genau den brauchen Sie für den Transport der Datenbasis auf den Slave.

Doch das reicht natürlich nicht ganz aus: Sie wollen die Daten ja nicht am Bildschirm ansehen, sondern in einer Datei speichern. Dazu leiten Sie einfach die Ausgabe in eine Datei um.

Bash> mysqldump database > sicherung.sql

Die Sicherungskopie enthält dabei sowohl die Struktur Ihrer Tabellen als auch die zugehörigen Daten. Um die Daten aus der Sicherungskopie auf dem Slave wieder einzuladen, verwenden Sie:

bash> mysql < sicherung.sql

Wenn Sie sich nicht auf dem Server befinden, auf dem auch der MySQL-Dämon läuft, müssen Sie mysqldump mitteilen, von welchem Server es die Daten abholen soll. Dazu gibt es die Option -host=RemoteHost, bei der Sie statt RemoteHost den Server mit dem MySQL-Dämon angeben.

Dies erzeugt besonders bei großen Datenbanken jede Menge Traffic - das größte Problem beim Sichern mit mysqldump über das Netz. Für eine lokale Sicherung stellt das Programm hingegen das optimale Werkzeug dar.

Dateien kopieren: Manuelles Backup

Wenn Sie Ihren Master für die Zeit der Sicherungskopie kurz anhalten können, gibt es eine extrem einfache Methode, um die Daten zu sichern: Kopieren Sie bei angehaltenem MySQL-Server einfach alle Dateien Ihrer Datenbank auf den Slave. Natürlich muss auch dort MySQL angehalten werden. Danach können Sie den MySQL-Dämon einfach wieder starten - was Sie aber erst tun sollten, wenn Sie das Binary-Log eingeschaltet haben.

Zu kopieren sind dabei alle *.FRM-, *.MYD- und *.MYI-Dateien aus dem Datenbankverzeichnis der zu sichernden Datenbank. Dieser Weg ist der klarste und handlichste - jedoch mit zwei Einschränkungen. Zum einen müssen Sie den MySQL-Dämon anhalten. Das mag bei kleinen Datenbanken, Webseiten mit wenig Traffic oder Intranet-Sites mit klaren Wartungszeiten kein Problem darstellen. Bei großen öffentlichen Seiten, die jederzeit verfügbar sein sollen, ist dies jedoch vielleicht nicht möglich.

Der zweite Nachteil ist der, dass Sie für diese Methode einen Shell-Zugriff auf dem Datenbank-Server haben müssen: Diese Methode der Sicherung funktioniert also nicht, wenn Sie nur über einen kleinen Server bei einem Hosting-Provider verfügen.

Wenn Sie mehrere Slaves betreiben wollen, können Sie natürlich den gleichen Datenbestand auch auf mehrere Systeme kopieren. Der Master selbst überwacht die Slaves nicht, Sie können nach der Inbetriebnahme am Master aber nachsehen, ob, welche und wie viele Slaves momentan auf Updates vom Server warten. Dazu verwenden Sie das Kommando SHOW PROCESSLIST auf der MySQL-Kommandozeile.

Master/Slave: Das Setup Schritt für Schritt

Es gibt verschiedene Wege, ein Master/Slave-System Schritt für Schritt einzurichten, die im Folgenden vorgestellte Methode ist die einfachste. Sie ist jedoch nicht in allen Fällen anwendbar - trotzdem können Sie sich daran genügend orientieren, um auch bei anderen Gegebenheiten an einen laufenden Slave zu gelangen.

Zunächst stellen Sie sicher, dass Ihre beiden MySQL-Installationen für die Replikation kompatibel zueinander sind. Nicht alle Versionen von MySQL können alle anderen Versionen von MySQL replizieren. Am einfachsten ist es, wenn Sie auf allen Rechnern eine aktuelle MySQL-Variante einsetzen. Ist dies nicht realisierbar, dann können Sie diese Übersichtstabelle verwenden, um zu überprüfen, ob die Replikation mit Ihren Versionen möglich ist.

Nach der Sicherstellung dieser Voraussetzung legen Sie auf dem Master einen neuen Account an. Dieser ist ausschließlich für die Replikation zuständig. Der neue Account benötigt nicht viele Rechte, er braucht aber unbedingt das Privileg "Replication Slave", beziehungsweise bei Versionen unter 4.0.2 das Privileg "File". Diesen Account legen Sie ganz normal mit dem MySQL-Befehl GRANT an:

mysql> GRANT REPLICATION SLAVE ON *.* TO slave@'%.ihredomain.de' IDENTIFIED BY 'ihrPasswort';

"slave" steht in diesem Fall für den Namen des Accounts, "ihredomain.de" für den Namen Ihrer Domain und "ihrPasswort" für das zu verwendende Passwort.

Datenbank zum Master ernennen

Da der laufende MySQL-Dämon per Default kein Master ist und auch kein Binary-Log verwendet, müssen Sie beides aktivieren. Dazu tragen Sie zwei Optionen in der Datei my.cnf des Masters ein:

[mysqld]
log-bin
server-id=1

"log-bin" aktiviert das binäre Log. Die Server-ID ist einfach eine Nummer, mit der der Server identifiziert wird. Welche ID Sie vergeben, ist egal, es muss aber eine positive Zahl sein. Nachdem Sie die Änderungen an my.cnf vorgenommen haben, starten Sie den MySQL-Server neu. Dann flushen Sie alle Tabellen und blockieren außerdem Schreibzugriffe:

mysql> FLUSH TABLES WITH READ LOCK;

Jetzt ist es ungemein wichtig, dass Sie den mysql-Client, auf dem Sie soeben die Schreibzugriffe blockiert haben, nicht beenden. Tun Sie dies dennoch, wird auch der Schreibschutz aufgehoben. Es darf aber im Verlauf der folgenden Prozedur auf keinen Fall in die Datenbank geschrieben werden.

Snapshot des Masters anlegen

Jetzt legen Sie einen Snapshot der Daten des Masters an. Das geht am einfachsten, indem Sie das komplette Datenverzeichnis des Masters per tar in ein Archiv verpacken. Sie wechseln also in das Datenverzeichnis Ihrer MySQL-Installation und verwenden das folgende Kommando:

bash> tar -cvf /tmp/master-snapshot.tar .

Die tar-Datei kopieren Sie an zwei Stellen:

Im Datenverzeichnis des Slave packen Sie die tar-Datei wieder aus.

bash> tar -xvf master-snapshot.tar

Neben dem tar-Archiv brauchen Sie auch die aktuelle Position des Binary-Logs auf dem Master. Diese Information sichern Sie am besten ebenfalls auf der Backup-CD, denn nur zusammen mit dieser Information können Sie später andere Slaves aufsetzen. Die Position des Binary-Logs erhalten Sie mit SHOW MASTER STATUS; auf der MySQL-Konsole.

Wenn das erledigt ist, können Sie Schreibzugriffe auf dem Master wieder gestatten. Sie wechseln also zum noch laufenden MySQL-Client:

mysql> unlock tables;

Slave-Rechner vorbereiten

Jetzt müssen Sie wieder zum Slave-Rechner wechseln und dessen my.cnf bearbeiten. Hier ist nur eine Server-ID anzugeben:

[mysqld]
server-id=2

Die Nummer des Slave muss sich von der des Servers unterscheiden. Eine "1" für den Master und eine "2" für den Slave zu verwenden, ist also einigermaßen logisch. Wenn Sie mehrere Slaves verwenden, müssen alle Slaves unterschiedliche IDs aufweisen.

Nach der Änderung in der my.cnf des Slave ist dieser neu zu starten. Danach teilen Sie dem Slave mit, dass er ab sofort Daten vom Master abholen soll. Das müssen Sie nur ein einziges Mal tun.

mysql> CHANGE MASTER TO
-> MASTER_HOST='NameDesMasters',
-> MASTER_USER='slave',
-> MASTER_PASSWORD='ihrPasswort',
-> MASTER_LOG_FILE='LogFile',
-> MASTER_LOG_POS='offset';

NameDesMasters steht für den Namen des Masters, slave für den Namen des Accounts für die Replikation und ihrPasswort ist das dazugehörige Passwort. Über LogFile teilen Sie dem Slave den Namen des Binary-Logs des Masters aus dem Snapshot mit - im Beispiel also database-bin.045 - und über offset die Position im Binary-Log, im Beispiel 14468606.

Slave-Betrieb starten

Damit sind Sie im Prinzip fertig: Sie müssen allerdings noch den Slave-Thread auf dem Slave starten. Dies ist nur ein Mal erforderlich, denn der MySQL-Dämon merkt sich, dass er als Slave fungiert.

mysql> START SLAVE;

Nach dem Absenden dieses Kommandos nimmt der Slave direkt Kontakt mit dem Server auf und holt alle angefallenen Updates ab.

Wichtig dabei: Bei einigen Versionen von MySQL lautet das Kommando nicht START,SLAVE sondern SLAVE START.

Damit ist alles erledigt: Sie verfügen nun über eine funktionierende Master/Slave-Installation. (mha)