GTID (Global Transaction ID)?
Der Begriff GTID lässt erahnen, dass jeder Transaktion eine eindeutige ID zugewiesen wird. Der Server, der die Transaktion durchführt, berechnet beim Commit die ID. Sie setzt sich aus zwei Teilen zusammen: der Server UUID und einer fortlaufenden Nummer der Transaktion.
Für ein bestehendes Replikationssetup zwischen Master und Slave(s) gilt ebenfalls, dass GTIDs eindeutig sein müssen. Über das gesamte Master-Slave-Gespann wird eine 1-zu-1-Zuordnung zwischen GTIDs und ausgeführten Transaktionen gepflegt. Diese Information reicht aus, um komplexe Setups zu betreiben, da die MySQL-Server stets wissen, welche Transaktionen auf welchen Servern bereits ausgeführt wurden.
Der GTID-Lebenszyklus im Detail:
1. Der Master führt eine Transaktion durch und wählt die nächste freie GTID aus. Für die Replikation werden beide Teile in das Binary Log geschrieben.
2. Die Binary Logs werden auf Seiten des Slave geholt und ins Relay Log übertragen. Der Slave liest die GTID aus und übernimmt den Wert in die Variable „gtid_next“.
3. Bevor sich der Slave der Transaktion annimmt, prüft er, ob die GTID bereits in seinem eigenen Binary Log vorkommt. Nur wenn das nicht der Fall ist, führt der Slave die Transaktion durch.
4. Der Umweg über die Variable „gtid_ next“ verhindert, dass der Slave eine neue GTID erstellt. Stattdessen korrelieren die Daten zwischen Master und Slave, was das GTID-Transaktions-Paar betrifft.
Quelle: admin-magazin.de
MariaDB-Knowledge Base: https://mariadb.com/kb/en/gtid/
Einrichten der Master-Master Replikation
Vorbereitungen
Ich habe zum einrichten zwei VMs mit jeweils einer frischen Minimal-Installation von Centos8 mit neu installierten Mariadb-Server (Version: 10.3.17).
mysql01: 192.168.2.49
mysql02: 192.168.2.50
Direkt nach der Installation ist der Mariadb/MySQL-Dienst noch nicht gestartet, dies nutzen wir um die folgenden zusätzlichen Parameter in die /etc/my.cnf.d/mariadb-server.cnf
in den Abschnitt [mysqld]
zu setzen.
auto_increment_increment = 2
auto_increment_offset = 1
gtid_domain_id = 1
gtid_ignore_duplicates = ON
gtid_strict_mode = ON
replicate_ignore_db = mysql
replicate_ignore_db = performance_schema
replicate_ignore_db = information_schema
server_id = 1
binlog_format = mixed
log_bin = /var/lib/mysql/bin-log
log_slave_updates = 1
relay_log = /var/lib/mysql/relay-log
Erläuterungen:
auto_increment_increment
und auto_increment_offset
werden für eine Master-Master Replikation empfohlen. Weitere Infos dazu: dev.mysql.com
gtid_domain_id
wird hierbei, da es sich um eine parallel Replikation handelt benötigt.
Wichtig: diese muss auf den jeweiligen Systemen unterschiedlich sein.
gtid_ignore_duplicates
Wenn diese Option aktiviert ist, können verschiedene Master-Verbindungen in der Replikation mit mehreren Quellen Ereignisgruppen mit derselben GTID empfangen und verarbeiten (bei Verwendung des GTID-Modus).
Es wird nur eine angewendet, alle anderen werden ignoriert. Innerhalb einer bestimmten Replikationsdomäne wird nur die Sequenznummer verwendet, um zu entscheiden, ob eine bestimmte GTID bereits angewendet wurde.
Dies bedeutet, dass es in der Verantwortung des Benutzers liegt, sicherzustellen, dass die GTID-Sequenznummern streng ansteigen. Mit gtid_ignore_duplicates = OFF
wird ein doppeltes Ereignis basierend auf der Domänen-ID und der Sequenznummer ausgeführt.
Infos: mariadb.com
gtid_strict_mode
Infos: mariadb.com
replicate_ignore_db
Mit diesem Parameter können bestimmte Datenbanken von der Replikation ausgeschlossen werden.
server_id
Setzt die Server-ID, welche in den binlog
Ereignissen protokolliert wird.
Dies wird von mysqlbinlog verwendet, um die Server-ID von GTID-Ereignissen beizubehalten.
WICHITG: Die Server-ID sollten auf den entsprechenden Systemen unterschiedlich sein.
log_bin
gibt an unter welchem Pfad die binlogs
abgelegt werden sollen.
relay_log
gibt an unter welchem Pfad das Relay-Log abgelegt werden soll.
log_slave_updates
Normalerweise protokolliert ein Slave keine Updates, die von einem Master-Server empfangen werden, in seinem eigenen Binärprotokoll. Durch Aktivieren dieser Variablen schreibt der Slave die von seinem SQL-Thread durchgeführten Aktualisierungen in seine einen binlogs
.
Nun wird der mariadb
Dienst per systemctl restart mariadb.service
neu gestartet.
Als letzten wird auf beiden Systemen noch ein entsprechender Replikations-Benutzer eingerichtet. Dies geschieht per:
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'replication'@'192.168.2.%' identified by '123456';
Query OK, 0 rows affected (0.001 sec)
Nun aktualisiert man noch die MySQL-Benutzer:
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.001 sec)
Einrichtung der Replikation
Abfragen der GTID
Position
Als erstes richten wir eine einfache Master-Slave Replikation ein.
Hierbei wird nun der mysql01 der Master und der mysql02 der Slave.
Nun fragen wir auf dem ersten zukünftigen Master (mysql01) den aktuellen Master-Status ab um die aktuelle binlog
Position zu bekommen.
MariaDB [(none)]> show master status;
+----------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------+----------+--------------+------------------+
| bin-log.000003 | 676 | | |
+----------------+----------+--------------+------------------+
1 row in set (0.000 sec)
Damit bekommen wir die eigentliche GTID
Position:
MariaDB [(none)]> select binlog_gtid_pos('bin-log.000003',676);
+---------------------------------------+
| binlog_gtid_pos('bin-log.000003',676) |
+---------------------------------------+
| 1-1-46 |
+---------------------------------------+
1 row in set (0.001 sec)
Einrichten des Slave mit GTID
Position
Auf dem zukünftigen Slave (mysql02) führen wir nun die folgenden Schritte aus:
1.) Anhalten des Slave
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected, 1 warning (0.000 sec)
2.) Reseten des Masters
MariaDB [(none)]> RESET MASTER;
Query OK, 0 rows affected (0.126 sec)
HINWEIS: Dies wird nur bei der initialen Einrichtung auf dem ersten MasterSystem verwendet um einen sauberen Stand zu haben.
3.) Setzen der GTID
als aktuelle Slave-Position
MariaDB [(none)]> set global gtid_slave_pos="1-1-46";
Query OK, 0 rows affected (0.042 sec)
4.) Setzen des Masters, des Replikationsbenutzers, etc.
Hierbei sollte man den Eintrag master_use_gtid=slave_pos
beachten, welcher dafür sorgt, dass GTID
s verwendet werden.
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.2.49', MASTER_USER='replication', MASTER_PASSWORD='123456', master_use_gtid=slave_pos;
Query OK, 0 rows affected (0.480 sec)
5.) Starten des Slave
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.383 sec)
Nun sollte bei einem Aufruf von show slave status\G
eine laufende Replikation zu sehen sein:
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.2.49
Master_User: replication
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: bin-log.000003
Read_Master_Log_Pos: 676
...
Using_Gtid: Slave_Pos
Gtid_IO_Pos: 1-1-46
...
Einrichten der Master-Master Replikation
Um nun auch den mysql01 zum weiteren Slave und den mysql02 zum weiteren Master zu machen gehen die Schritte nochmals durch, aber auf den jeweils anderen Systemen.
HINWEIS: Damit der jetzige Slave (mysql02) eine GTID
anzeigen kann muss dieser zuvor eine entsprechende Transaktion ausführen, damit diese erstellt wird.
Hierfür reicht eine kurze Erzeugung einer neuen Datenbank:
MariaDB [(none)]> CREATE DATABASE foobar2;
Query OK, 1 row affected (0.002 sec)
Nun fragen wir auf dem zukünftigen neuen Master (mysql02) die aktuelle binlog
Position ab um die GTID
abzufragen.
MariaDB [(none)]> show master status;
+----------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------+----------+--------------+------------------+
| bin-log.000001 | 882 | | |
+----------------+----------+--------------+------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> select binlog_gtid_pos('bin-log.000001',882);
+---------------------------------------+
| binlog_gtid_pos('bin-log.000001',882) |
+---------------------------------------+
| 1-1-3,2-2-2 |
+---------------------------------------+
1 row in set (0.001 sec)
Hier sieht man nun, dass bereits eine GTID
Domain dazu gekommen ist.
Auf dem neuen zusätzlichen Slave (mysql01) führen wir die folgenden Schritte aus:
1.) Slave stoppen
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected, 1 warning (0.000 sec)
2.) GTID
setzen
MariaDB [(none)]> set global gtid_slave_pos="1-1-3,2-2-2";
Query OK, 0 rows affected (0.032 sec)
3.) Setzen der Master Daten
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.2.50', MASTER_USER='replication', MASTER_PASSWORD='123456', master_use_gtid=slave_pos;
Query OK, 0 rows affected (0.029 sec)
4.) starten des Slaves
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.016 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.2.50
Master_User: replication
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: bin-log.000001
Read_Master_Log_Pos: 882
...
Using_Gtid: Slave_Pos
Gtid_IO_Pos: 1-1-4,2-2-2
...
Damit ist die Master-Master Replikation fertig.