Immer wieder kommt es bei Beratungseinsätzen in Sachen MySQL zu kleineren oder größeren Problemen, über die wir an dieser Stelle gerne berichten möchten. In diesem Fall wollte unser Kunde eine MySQL Single Instance durch ein MySQL InnoDB Cluster mit drei Knoten ablösen. Über den Cluster haben wir an dieser Stelle mehrfach berichtet [1-5] und möchten hier nicht mehr im Detail darauf eingehen.
In diesem konkreten Fall gab es ein vermeintliches einfaches Problem. Eine wesentliche Voraussetzung für die Inbetriebnahme des Clusters war schlicht und einfach nicht erfüllt: Es gab Tabellen ohne Primary Key!
Gute Voraussetzungen haben …
Der MySQL InnoDB Cluster basiert auf der sogenannten „Group Replication“. Zur Verwendung dieses „Features“ müssen alle Tabellen die Storage Engine InnoDB verwenden und über einen Primary Key verfügen. Weitere Anforderungen zur Verwendung der „Group Replication“ bzw. des InnoDB Clusters finden Sie hier.
Der Kunde hatte neben dem eigentlichen, bereits im Betrieb befindlichen, Datenbank-Server drei weitere Knoten bereitgestellt, die zu einem Cluster zusammengefügt wurden.
In unserer Testumgebung haben wir das Problem stark vereinfacht mit vier Docker-Containern nachgestellt. Auf dem initialen Knoten („Altsystem“ mit dem Namen: Berlin) liegt eine Datenbank mit dem Namen „application“, die über eine Tabelle „names“ verfügt. Die anderen drei Container (Hamburg, Cologne, Frankfurt) repräsentieren das Cluster.
Hier ein kleiner Überblick über das Datenmodell:
Wie unschwer zu erkennen ist, verfügt die Tabelle „names“ nur über zwei Spalten vom Typ „varchar“, aber besitzt keinen Primary Key.
Unter schlechten Bedingungen leiden …
Bereits vor der eigentlichen Initialisierung des Clusters konnten die Fehler „aufgespürt“ werden. Zu diesem Zeitpunkt befand sich bereit in einem der Knoten der zu bauenden Clusters (Hamburg) eine importierte Version der Datenbank „application“. Mittels der folgenden Prüfroutine sollte im Vorfeld (vor dem Aufbau des Clusters) verifiziert werden, ob das System/die Systeme überhaupt für den Aufbau eines Clusters geeignet wäre. Bereits im ersten Schritt (Aufruf der Prüfroutine auf dem ersten Knoten) stellte sich raus, wir haben ein Problem:
Es fehlt ein Primary Key auf der Tabelle „names“! Bei unserem Kunden trat dieser Fehler leider nicht nur 1x, sondern mehrfach auf.
Man muss sich zu helfen wissen …
Natürlich ist es nicht schwer, einen (!) Primary Key nachzupflegen. Allerdings wollten wir hier nicht von „Hand“ tätig werden. Zusätzlich muss man bedenken, dass das Hinzufügen einer neuen Spalte bei diversen Tabellen ggf. Probleme innerhalb der Applikation verursachen kann. So könnte es sein, dass ein Entwickler an der einen oder anderen Stellen eine „select * from tabX“ nutzt und eine bestimmte Anzahl an Ergebnisspalten erwartet. Taucht hier eine zusätzliche angelegte Spalte, die als Primary Key genutzt wird, plötzlich aus, so könnte dies zu einem Fehler führen. Wir haben uns entschlossen, die neue Funktion „Generated Invisible Primary Keys“ zu nutzen, die ab der Version 8.0.30 zur Verfügung steht. Doch bevor wir mit dem Kundenbeispiel fortfahren, ein kurzer Exkurs, was dieser Parameter eigentlich auf einem Datenbanksystem verändert.
Letztendlich sorgt die Einstellung dafür, dass Tabellen, die ohne expliziten Primary Key erstellt werden, zwangsweise einen ebensolchen bekommen. Dieser Primary Key heißt stets: „my_row_id“.
Hier ein kleines Fallbeispiel:
Wie zu erkennen ist, wird das neue „Feature“ per default nicht verwendet. Erstellen wir zum Test eine kleine Tabelle „tab1“ ohne diese Konfiguration zu aktivieren.
Tabellen, die wie oben ohne Primary Key erzeugt werden, bekommen dann folglich auch keinen!
Nach der Aktivierung dieser Funktion ändert sich dieses Verhalten:
Die Tabelle hat nun automatisch den Primary Key „my_row_id“ bekommen.
Gut versteckt sein …
Doch wie sieht es aus mit der Sichtbarkeit des Primary Keys. Über die Anweisung „show create table“ kann man die zusätzliche Spalte mit dem Primary Key erkennen. Doch wie sieht es mit der oben erwähnten „select * from“-Variante aus, die ein Entwickler ggf. verwendet hat:
Ok, die Spalte wird nicht mit ausgegeben. Doch ist dies immer so? Ggf. versucht die Applikation das Datenmodell über andere Mechanismen zu validieren:
- „desc table“
- Systemtabellen
Prüfen wir auch dies:
Auf diesem Weg bekommen wir quasi einen „Existenzbeweis“ für die Spalte und den Primary Key. Natürlich gibt es auch hier einen kleinen „Tweak“, um das Verhalten der Datenbank „anzupassen“:
Wie wir sehen, sehen wir nichts!
Es ist immer gut einen Plan zu haben …
Der Plan (nicht alle Schritte werden wir hier erklären) für den Kunden zum Aufbau des Clusters sieht wie folgt aus:
1. Aufbau des neuen Clusters mit den Knoten Hamburg, Cologne, Frankfurt.
2. Aktivierung der Funktion „Generated Invisible Primary Keys“ im Cluster.
3. Aufbau einer Replikation vom Altsystem „Berlin“ in das Cluster hinein (zum primären Knoten „Hamburg“).
4. Backup und Restore der Datenbank „application“ in das Cluster.
5. Starten der Replikation.
6. Umschalten vom Altsystem auf das Cluster.
Das Problem der fehlenden Primary Key sollte sich gemäß dem Plan mit dem dritten Schritt von selbst erledigen. Alle Tabellen, die mit dem Restore des Dumps ohne Primary Keys erstellt werden, bekommen nun per default einen eben solchen.
Nach dem Aufbau des Clusters (Schritt 1), den wir uns an dieser Stelle im Detail „schenken“, wird der entsprechende Parameter aktiviert:
Auch die Replikation zwischen dem primären Cluster (Knoten „Hamburg“) und dem Alt-System („Berlin“) wurde eingerichtet (Schritt 3), ohne dies hier im Detail zu beschreiben. Allerdings ist die Replikation noch nicht aktiv.
Mit dem Einspielen des Backups von Knoten „Berlin“ (Alt-System) in das Cluster (Knoten Hamburg) werden die Tabellen neu angelegt. Aufgrund der obenstehenden Konfiguration werden die fehlenden Primary Keys erzeugt.
Schauen wir uns (zur Sicherheit) einmal das Ergebnis an. Wie wurde die Tabelle „names“ in der Datenbank „application“ im Cluster angelegt?
Der fehlende Primary Key ist vorhanden.
Schön, wenn ein Plan funktioniert …
Der Plan ließ sich also erfolgreich umsetzen. Der MySQL-Dump vom Alt-System konnte erfolgreich in das Cluster eingespielt werden. Alle fehlenden Primary Keys wurden über die generierten Schlüssel kompensiert. Hätte dies nicht funktioniert, so wäre es bereits an dieser Stelle zu einem Problem gekommen, da, wie wir am Anfang bereits gelernt haben, Tabellen ohne Primary Keys nicht in ein Cluster einspielen werden können. Sicherlich hätte man das Problem des Kunden auch anders lösen können. Das neue „Feature“ hat an dieser Stelle viel manuelle Arbeit eliminiert und uns effizient zum Ziel gebracht.
Sie haben Fragen rund um das Thema MySQL? Dann sprechen Sie mit uns!
Links
[1] MySQL Shell - Cluster Your Application In 40 Minutes
[2] MySQL 8.0.19: Wie ein Ei dem anderen
[3] MySQL InnoDB Cluster: "Schlüsselmomente" beim Import
[4] Doppelt gemoppelt: Wie man Cluster “clustered”. MySQL-InnoDB-ClusterSets
[5] Ein Geheimnis behalten: MySQL Router „Bootstrapping“ ohne „root“-Account
Seminarempfehlung
MYSQL ADMINISTRATION DB-MY-01
Zum Seminar