Juli 2014 Archive

Wer GTID nutzt um einen asynchronen Slave an einen Galera Cluster anzuschließen sollte wissen, dass die Integration von GTID und Galera je nach GTID Implementierung anders aussieht.

GTID@MariaDB

Jeder Node erhöht für sich seine Seqno. Solange alle Transaktionen via Galera erhöht werden, welches sich um die Commit Order der Daten kümmert, gibt es auch keine Probleme und die GTID (Seqno) sind überall identisch. (Wenn die ursprüngliche Seqno auch identisch war ;)

  node1> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-504 |
  +-----------------+---------+

  node2> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-504 |
  +-----------------+---------+

  node3> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-504 |
  +-----------------+---------+

Doch was wenn eine DML ausgeführt wird, welches nicht via Galera Repliziert wird?

Nehmen wir an, auf node1 wird in eine MyISAM/MEMORY etc. Tabelle geschrieben. Dann erhöht sich die Seqno nur auf node1.

  node1> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-505 |
  +-----------------+---------+

  node2> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-504 |
  +-----------------+---------+

  node3> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-504 |
  +-----------------+---------+

Die Galera Replikation stört das nicht. So erhöht z.B. ein weiterer Insert in eine InnoDB Tabelle alle Seqno’s:

  node1> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-506 |
  +-----------------+---------+

  node2> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-505 |
  +-----------------+---------+

  node3> show global variables like 'gtid_binlog_pos';
  +-----------------+---------+
  | Variable_name   | Value   |
  +-----------------+---------+
  | gtid_binlog_pos | 0-1-505 |
  +-----------------+---------+

Damit gibt es keine eindeutige Zuordnung von den GTID@MariaDB zu den GTID@Galera (im Binlog) mehr. Dies ist mehr als ungünstig.

Wenn nun ein Slave von einem Node zu einem anderen wechselt. Werden entweder

  • Transaktionen verloren gehen.
  • Transaktionen nochmal ausgeführt werden.

Abgesehen davon, dass der Sinn der GTID ad absurdum geführt ist.

Wenn die Replikation sich mit einem Fehler beendet ist es noch gut. Was bedeutet das? Wer an einen MariaDB Galer Cluster einen asynchronen Slave (GTID) anschließt muss streng darauf achten, dass nur Queries im Cluster ausgeführt werden, die via Galera Repliziert werden.

GTID@MySQL(Percona)

Hier sieht es anders aus. Die GTID bei MySQL wird durch die server_uuid bestimmt. Hier macht Galera einen Trick. Für alle Transaktionen, welche via Galera repliziert werden, gibt es eine eigene server_uuid.

Betrachten wir nur einen Node

 node2> show global variables like 'gtid_executed';
 +---------------+-------------------------------------------------+
 | Variable_name | Value                                           |
 +---------------+-------------------------------------------------+
 | gtid_executed | 6d75ac01-ed37-ee1b-6048-592af289b902:1-10,
 933c5612-12c8-11e4-82d2-00163e014ea9:1-6 |
 +---------------+-------------------------------------------------+

6d75ac01-ed37-ee1b-6048-592af289b902 ist die server_uuid für Galera. 933c5612-12c8-11e4-82d2-00163e014ea9 ist die server_uuid für alle anderen Transaktionen.

Schreiben wir in eine InnoDB Tabelle erhöht sich Galeras Seqno und ist auf allen Nodes gleich.

node2> node2> show global variables like 'gtid_executed';
+---------------+--------------------------------------------------+
| Variable_name | Value                                            |
+---------------+--------------------------------------------------+
| gtid_executed | 6d75ac01-ed37-ee1b-6048-592af289b902:1-11,
933c5612-12c8-11e4-82d2-00163e014ea9:1-6 |
+---------------+--------------------------------------------------+

node1>  show global variables like 'gtid_executed';
+---------------+--------------------------------------------------+
| Variable_name | Value                                            |
+---------------+--------------------------------------------------+
| gtid_executed | 6c7225e2-12cc-11e4-8497-00163e5e2a58:1-2,
6d75ac01-ed37-ee1b-6048-592af289b902:1-11 |
+---------------+--------------------------------------------------+

Ein Insert in z.B. eine MyISAM Tabelle nur auf node2 erhöht

node2> show global variables like 'gtid_executed';
+---------------+------------------------------------------------------+
| Variable_name | Value                                                |
+---------------+------------------------------------------------------+
| gtid_executed | 6d75ac01-ed37-ee1b-6048-592af289b902:1-11,
933c5612-12c8-11e4-82d2-00163e014ea9:1-7 |
+---------------+------------------------------------------------------+

Das hat zur Folge, dass via Galera replizierte Transaktionen überall das gleiche Mapping von GTID@MySQL und GTID@Galera (im Binlog) haben. Nicht Galera-Transaktionen werden separat abgespeichert.

Wenn ein Slave seinen Master wechselt, ist er in Puncto der Galera Daten synchron. Andererseits wird der Salve sich alle anderen DMLs der Master auch zu eigen machen. Welches auch zum Abbruch der Replikation führen kann.

Resumé

Laufen auf dem Cluster nur Queries welche via Galera repliziert werden ist die Wahl der GTID Implementierung egal. Aber spätestens nach einem Rolling Upgrade mit verbundenem mysql_upgrad hat man mit GTID@MariaDB verloren.

Imho wäre es naheliegend eine eigene domainid von GTID@MariaDB dazu zu nutzen Galera Transaktionen zu speichern und auf dem Slave nach domainid filtern zu können. Mal sehen ob sich MariaDB überzeugen lässt :)

Viel Spaß

Erkan :)

Galera Replikation wie sie in Percona XtraDB Cluster, MariaDB Galera Cluster oder auch direkt in MySQL gepatcht zu finden ist, ist gegenüber der traditionellen MySQL Replikation (Master, Slave) agnostisch. Soll ein Node eines Galera Clusters als Master herhalten, reicht es auf diesem log_bin, log_slave_updates und eine server_id zu setzen und einen Slave ran zu hängen.

GTID von MariaDB verwenden

Bei der Replikation besteht die Auswahl zwischen der klassischen (Fileoffset) Replikation und Replikation unter Verwendung von GTID (Global Transaction ID). Da mit Verwendung der GTID die Fileoffsets nicht mehr gebraucht werden, verspricht die Verwendung von GTIDs einen einfachen Failover von einem Node als Master zu dem nächsten.

Nun gibt es je nach verwendetem MySQL(Fork) zwei verschiedene Implementierungen der GTID.

Die GTID bei MySQL/Percona und die GTID bei MariaDB.

Für den Aufbau eines Slaves mit klassischer (non GTID) Replikation sei verwiesen auf:

Einen Blog zur Verwendung von den GTID bei MySQL/Percona sei hierauf verwiesen.

Was fehlt ist ein Blogpost zur Verwendung der GTID bei MariaDB.

Und genau dies folgt;)

Ein laufender MariaDB Galera Cluster ist vorausgesetzt. Zur Installation eines (MariaDB) Galera Clusters siehe hier: erkules

Anders als im Blog beschrieben bitte wsrep_sst_method=xtrabackup-v2nutzen. Die aktuelle MariaDB 10.0.12-MariaDB-1~trusty-wsrep-log hat einen Bug

Konfiguration auf Cluster Seite

Zusätzlich zu der obigen Galera Konfiguration brauchen designierte Master

[mysqld]
log_bin
log_slave_updates
server_id        = 1

log_bin aktiviert das Binlog und mit log_slave_updates werden auch via Galera replizierte Schreibvorgänge (anderer Nodes) in das Binlog geschrieben. Wie bei Replikation üblich ist die server_idzu setzen. Aus didaktischen Gründen kann die server_id bei allen Cluster Nodes identisch sein. Da die Galera Replikation ist gegenüber der MySQL Replikation agnostisch ist ist die identische Verwendung von server_id möglich.

Aufbau eines Slaves

Die Slave Konfiguration muss auch noch erweitert werden:

[mysqld]
binlog_format      = ROW
log_bin
log_slave_updates
server_id          = 2

Der GTID Support von MariaDB ist noch nicht so praxistauglich. So werden die GTID weder mit mysqldump noch mit xtrabackup gepeichert.

Für mysqldump gibt es ab MariaDB 10.0.13 eine Abhilfe. Für das von Percona entwickelte xtrabackup gibt es einen Patch. Mal sehen wann der integriert wird.

Die Herangehensweise ist simple.

Da MariaDB - im Gegensatz zu MySQL - die GTID immer mit repliziert. Erstellen wir ein klassisches (master-data)Backup starten den Slave und wechseln dann auf GTID Replikation.

Wie ein Slave aufgebaut wird sparen wir uns. Wir hüpfen direkt in die laufende Replikation:

MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.3.93
                  Master_User: replication
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysqld-bin.000002
          Read_Master_Log_Pos: 537
               Relay_Log_File: mysqld-relay-bin.000002
                Relay_Log_Pos: 536
        Relay_Master_Log_File: mysqld-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 537
              Relay_Log_Space: 834
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
             Master_Server_Id: 1
                   Using_Gtid: No
                  Gtid_IO_Pos:

Der Wechsel zu GTID basierten Replikation ist simpel:

slave> stop slave;
slave> change master to master_use_gtid=slave_pos;
slave> start slave;
slave> show slave status\G

*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.3.93
                  Master_User: replication
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysqld-bin.000002
          Read_Master_Log_Pos: 873
               Relay_Log_File: mysqld-relay-bin.000002
                Relay_Log_Pos: 694
        Relay_Master_Log_File: mysqld-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 873
              Relay_Log_Space: 992
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
        Seconds_Behind_Master: 0
             Master_Server_Id: 1
                   Using_Gtid: Slave_Pos
                  Gtid_IO_Pos: 0-1-3

Man achte auf die beiden letzten Einträge.

Failover

Fällt der gegenwärtige Master aus, kann einfach geswitcht werden:

 slave> STOP SLAVE;
 slave> CHANGE MASTER TO MASTER_HOST="$NEW_HOST";
 slave> START SLAVE;

Mach achte auf auf den Wert für Master_Host:

 slave> show slave status\G
 *************************** 1. row ***************************
                Slave_IO_State: Waiting for master to send event
                   Master_Host: 10.0.3.189
                   Master_User: replication
                   Master_Port: 3306
                 Connect_Retry: 10
               Master_Log_File: mysqld-bin.000007
           Read_Master_Log_Pos: 77357
                Relay_Log_File: mysqld-relay-bin.000002
                 Relay_Log_Pos: 46594
         Relay_Master_Log_File: mysqld-bin.000007
              Slave_IO_Running: Yes
             Slave_SQL_Running: Yes
           Exec_Master_Log_Pos: 77357
               Relay_Log_Space: 46892
               Until_Condition: None
         Seconds_Behind_Master: 0
              Master_Server_Id: 1
                    Using_Gtid: Slave_Pos
                   Gtid_IO_Pos: 0-1-504

Damit ist das Failover viel einfacher als bei Replikation ohne GTID. Da bei diesem muss der passende Fileoffset auf dem neuen Master erst gefunden werden.

Auch wenn dies einfach zu funktionieren scheint, möchte ich von der Verwendung der GTID@MariaDB abraten. Siehe nächster Blogpost.

Viel Spaß

Erkan :)

Ahoi hier die Vorträge für das nächste Halbjahr:

MySQL Hochverfügbar mit Galera

Wo: FrOSCon

Was: Galera wird erklärt und mit LXC und Ansible aufgebaut :)

LBaaS-Loadbalancer as a Service

Wo: GUUG Frühjahrsgespräche

Was: Mit Jan Walzer und Jörg Jungermann gibt es einen Workshop zu in LXC gekapselten Loadbalancer Instanzen. Hier werden nur die Loadbalancer virturalisiert.

Medley der Containertechniken

Wo: GUUG Frühjahrsgespräche

Was: Wie schauen uns die Basics der Containertechniken im Kernel an (Namespaces, Cgroups und Chroot). Darauf hin schauen wir uns LXC, Libvrit, systemd-nspawn und Docker an.

MySQL Replikation: Von den Anfängen in die Zukunft

Wo: DOAG 2014

Was: Es wird einen Überblick über die Evolution der Replikation in MySQL und MariaDB geben.

Hands on Docker

Wo: CommitterConf.de  Was: In dem Workshop lernen wir Docker :)

Es gibt viele Gelegenheiten an denen man sich wünscht einem Dockercontainer eine feste IP zuweisen zu können. Zwar haben Dockercontainer IPs, doch diese sind:

  • volatil (Da bei einem Neustart die IPs neu vergeben werden.)
  • werden nicht geroutet. So sind sie von ausserhalb es Hosts nicht erreichbar.

Dockercontainer laufen im eigenem Namespace. Nun wollen wir mittels iproute2 dem dem Network Namespace der Containers noch ein Device anflanschen.

Schauen wir uns erst mal den Prozess an (gekürzt):

> docker ps
CONTAINER ID        IMAGE               COMMAND              NAMES
8fe4e6c72b90        erkan/nginx:v01     /bin/sh -c nginx     angry_mccarthy

ip netns kennt den Namespace des Containers nicht.

> ip netns
>

ip nents verwaltet seine Namespaces unter /var/run/netns. Daher müssen wir etwas tricksen.

Wir holen uns die IP des Containers:

> docker inspect --format='{{ .State.Pid }}' angry_mccarthy
26420

Und Linken einfach nach /var/run/netns/$wahlname

> ln -s /proc/26420/ns/net /var/run/netns/freeme
> ip netns
freeme

Jetzt erstellen wie uns ein veth-“Kabel” und stecken das andere Ende in das freeme Net Namespace.

> ip link add veth-host type veth peer name veth-freeme
> ip link set veth-freeme netns freeme

Da hier auf der Maschine schon eine Bridge ist, können wir gleich das andere Ende unseres Kabel an die Bridge flanschen, eine IP zuweisen und die Interfaces hoch fahren.

> ip link set veth-host master br0
> ip netns exec freeme ip addr add 192.168.178.123/24 dev veth-freeme
> ip netns exec freeme ip link  set veth-freeme up
> ip link set veth-host up

Und nun von einem anderen Rechner:

Ichbinwoanders:~$ curl  192.168.178.123
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>

feddisch \o/

Viel Spaß Erkan

P.S: http://www.opencloudblog.com (Ex Kollege von mir und gemein fit :)

Ahoi,
Es gibt nen DockerHaterHipsters Talk vom mir auf nem DockerMeetup.
Ist jetzt nicht mal so hater. Geht mir nur darum, dass wir schnell verstehen, dass es sich bei/um Docker nicht einfach um eine andere/neue Virtualisierungstechnik handelt.

Viel Spaß
Erkan :)