MySQL Replikation reparieren

Da bei mir aufgrund eines Stromausfalls einer meiner zwei Datenbankserver ausgefallen ist, funktionierte anschließend die Replikation nicht mehr. Ursache der defekten Replikation war natürlich das abrupte Ableben des Servers mangels Strom.

Hinweis:
Befehle die mit „mysql>“ Anfangen werden im MySQL Client ausgeführt. „hostname:#“ bezeichnet befehle, die auf der Shell ausgeführt werden.

Mit dem Befehl

mysql> show slave status \G;

kann man sich den Status des Slave-Servers übersichtlich anzeigen lassen:

****************** 1. row *******************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.100.2
Master_User: dbslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000262
Read_Master_Log_Pos: 761
Relay_Log_File: slave-relay.006566
Relay_Log_Pos: 235
Relay_Master_Log_File: mysql-bin.000262
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 761
Relay_Log_Space: 235
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0

Die zwei Werte Slave_IO_Running und Slave_SQL_Running geben den Status über die Replikation an. Slave_IO_Running steht dafür, das Daten vom Master empfangen werden. Slave_SQL_Running steht dafür das die Daten auch Lokal verarbeitet wurden.
In meinem Fall war es so, das Slave_SQL_Running auf „No“ Stand und deshalb keine Daten Lokal verarbeitet wurden. Wenn das der Fall ist steht unter Last_Error der aktuelle Fehler:

Last_Error: Error ‚Duplicate entry ‚86070024-0002586014-9′ for key 1‘ on query. Default database: ‚dbname‘. Query: ‚INSERT INTO tabelle (Feld1,Feld2) VALUES (‚Daten1′,’Daten2′)‘

Da es sich um einen bereits in der Datenbank befindlichen Datensatz gehandelt hat, war die Behebung des Problems ziemlich einfach. Dazu muss man lediglich MySQL sagen das er diesen Datensatz auslassen soll, da er ja bereits vorhanden ist.

Zunächst muss man die Replikation unterbrechen:

mysql> STOP SLAVE;

Anschließend soll MySQL einen Datensatz überspringen (kann auch mehr wie einer sein):

mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;

Nun muss man die Replikation wieder starten:

mysql> START SLAVE;

Abschließend sollte man den Slave Status wieder überprüfen:

mysql> show slave status \G;

Hierbei bekommt man bereits oben erklärte Ausgabe. Dabei ist besonders auf Slave_IO_Running und Slave_SQL_Running zu achten. Stehen beide auf „Yes“ und Last_Error ist leer, dann funktioniert die Replikation wieder.

Konsistenz Testen:

Um die Konsistenz der Daten zu testen führe ich auf beiden Servern einen Dump aus und vergleiche diese mittels einer Hashsumme. Um wirklich die gleichen Daten vergleichen zu können, sollten die Daten vor zugriffen durch andere Systeme bzw. User geschützt werden. Hierbei gibt es 2 Möglichkeiten. Entweder setzt man global oder auf die bestimmte Tabelle eine Sperre. Je nach Geschmack und vor lieben halt. Die folgenden Befehle müssen auf beiden Servern gleichzeitig ausgeführt werden.

Datenbank auswählen:

mysql> use dbname;

Tabelle vor anderen zugriffen schützen:
Global:

mysql> FLUSH TABLES WITH READ LOCK;

bzw. nur bestimmte Tabelle:

mysql> LOCK TABLES tabellenname READ;

Dump der Tabelle:

mysql> SELECT * FROM tabellenname INTO OUTFILE  "/tmp/dump_tabellenname.sql";

Die Sperrung kann jetzt wieder aufgehoben werden:
Global & nur bestimmte Tabelle:

mysql> UNLOCK TABLES;

MySQL Konsole verlassen und Hashsumme generieren:

mysql> quit;
hostname:# md5sum /tmp/dump_tabellenname.sql

Dabei bekommt man eine Ausgabe in der Form

bdd4f2fbf725d2b24aa60af4e16706fa /tmp/dump_tabellenname.sql

Die Zeichenkette vor dem Dateinamen ist der Hash und sollte mit dem vom zweiten Server verglichen werden. Sind beide gleich, sind die Daten auf beiden Servern konsistent.