gh-ost: triggerlose Schema-Migrationen über Binlog-Streaming
AI generated
InnoDB
SQL
MySQL / Binlog-basierte Migration
gh-ost: triggerlose Schema-Migrationen
Schemaänderungen über Binlog-Streaming statt über Trigger

Trigger-basierte Werkzeuge wie pt-online-schema-change lösen viele Probleme, erzeugen aber auf jeder einzelnen Schreiboperation zusätzlichen synchronen Aufwand. gh-ost, von GitHub entwickelt, verfolgt einen grundlegend anderen Ansatz: Es liest Änderungen asynchron aus dem MySQL-Binärlog, genau wie ein regulärer Replica-Server, und wendet sie auf eine Ghost-Tabelle an. Bei Tabellen mit sehr hoher, konstanter Schreiblast macht dieser Unterschied den entscheidenden Unterschied zwischen einer unbemerkten Migration und einer, die den produktiven Betrieb spürbar verlangsamt.

13 Min. Lesezeit Binlog-Streaming Throttling Atomic Cut-Over

1. Vom Trigger- zum Binlog-Ansatz: die Grundidee von gh-ost

gh-ost, kurz für GitHub's Online Schema Change, wurde bei GitHub entwickelt, nachdem pt-online-schema-change auf sehr großen, schreibintensiven Tabellen wiederholt an Grenzen stieß. Statt wie pt-osc synchrone Trigger auf der Originaltabelle zu installieren, verhält sich gh-ost gegenüber dem MySQL-Server wie ein ganz normaler Replica: es baut eine reguläre Replikationsverbindung auf und liest darüber den Strom aller Änderungsereignisse aus dem Binärlog.

Diese Änderungsereignisse wendet gh-ost anschließend asynchron auf eine separate Ghost-Tabelle an, parallel zum eigentlichen Kopiervorgang der bestehenden Daten. Der entscheidende Vorteil: die ursprüngliche Anwendung bemerkt von diesem Vorgang praktisch nichts, weil keine zusätzlichen Trigger auf der Originaltabelle laufen und jede reguläre Schreiboperation exakt so schnell bleibt wie vor der Migration.

2. Wie das Binlog-Streaming als Change-Data-Capture funktioniert

MySQL schreibt bei zeilenbasierter Replikation, also binlog_format=ROW, für jede geänderte Zeile ein vollständiges Vorher- und Nachher-Abbild in den Binärlog. gh-ost verbindet sich über das normale Replikationsprotokoll, meldet sich als Replica mit eigener Server-ID an und erhält darüber denselben Ereignisstrom, den auch ein regulärer Replica-Server empfangen würde. Aus diesem Strom filtert gh-ost gezielt nur die Ereignisse heraus, die die zu migrierende Tabelle betreffen.

Jedes gefilterte Ereignis wird intern in eine entsprechende Anwendung auf die Ghost-Tabelle übersetzt: ein Insert-Ereignis wird zu einem Insert, ein Update-Ereignis zu einem Update, ein Delete-Ereignis zu einem Delete. Weil dieser Prozess vollständig asynchron zur eigentlichen Anwendungsschreiboperation abläuft, entsteht dabei keinerlei zusätzliche Latenz für die Anwendung selbst, allenfalls eine geringe Verzögerung, bis eine Änderung auch in der Ghost-Tabelle ankommt.


# gh-ost benoetigt binlog_format=ROW als Voraussetzung
mysql -e "SHOW VARIABLES LIKE 'binlog_format';"

# Dry run gegen die Zieltabelle, keine Änderung an Produktionsdaten
gh-ost --host=db-primary.internal --database=magento --table=catalog_product_entity --alter="ADD INDEX idx_sku_type (sku, type_id)" --dry-run

3. Architekturvergleich zu pt-online-schema-change

Der Kernunterschied zwischen gh-ost und pt-online-schema-change liegt in der Frage, wo die zusätzliche Arbeit anfällt. Bei pt-osc entsteht sie synchron in derselben Transaktion wie jede Anwendungsschreiboperation, weil ein Trigger vor dem eigentlichen Commit ausgeführt werden muss. Bei gh-ost entsteht sie vollständig entkoppelt, in einem separaten Prozess, der den Binärlog irgendwann nach dem Commit ausliest und verarbeitet.

Diese Entkopplung bedeutet in der Praxis: eine Tabelle mit mehreren tausend Schreiboperationen pro Sekunde, etwa eine Sitzungs- oder Ereignis-Log-Tabelle in einem stark frequentierten Magento-Shop, spürt bei gh-ost keinen zusätzlichen Schreib-Overhead pro Anfrage. Der Preis dafür ist eine höhere Komplexität im Werkzeug selbst und eine gewisse, meist geringe Verzögerung, bis Änderungen aus dem Binärlog tatsächlich in der Ghost-Tabelle ankommen.

4. Voraussetzungen: Binlog-Format, GTID und Berechtigungen

Zwingende Voraussetzung ist binlog_format=ROW, statement- oder mixed-basierte Replikation reicht nicht aus, da gh-ost auf die vollständigen Vorher-Nachher-Zeilenabbilder angewiesen ist. Für den Datenbankbenutzer, mit dem gh-ost sich verbindet, sind mindestens die Rechte REPLICATION SLAVE und REPLICATION CLIENT nötig, zusätzlich die üblichen DML- und DDL-Rechte auf der Zieldatenbank.

Vor jedem produktiven Einsatz empfiehlt sich zusätzlich ein Testlauf über --test-on-replica, bei dem gh-ost die komplette Migration auf einem dedizierten Replica durchführt, dort die Replikation anhält und die Ergebnisse zwischen Original- und Ghost-Tabelle automatisch auf Konsistenz vergleicht, ganz ohne Auswirkung auf den produktiven Primärserver.

5. Der praktische Workflow: Test-Run, Dry-Run, Execute

Ein sinnvoller Ablauf beginnt mit einem --test-on-replica-Lauf gegen einen dedizierten Replica, gefolgt von einem --dry-run gegen den Primärserver, der alle Prüfungen durchführt, aber ohne tatsächliche Migration. Erst danach folgt der reale Lauf mit --execute, idealerweise außerhalb der Hauptlastzeiten, auch wenn gh-ost dank Throttling grundsätzlich auch während normaler Lastzeiten sicher laufen kann.

Während der Ausführung gibt gh-ost fortlaufend Statusinformationen aus: kopierte Zeilen, geschätzte Restlaufzeit, aktueller Durchsatz und aktuelle Replikationsverzögerung. Diese Ausgabe lässt sich zusätzlich über eine Unix-Socket-Schnittstelle interaktiv abfragen, was insbesondere bei Migrationen ohne direkten Terminalzugriff, etwa gestartet über einen CI-Job, wertvoll ist.


# Test-Run auf einem dedizierten Replica, keine Auswirkung auf den Primaerserver
gh-ost --host=db-replica.internal --database=magento --table=sales_order_grid --alter="ADD COLUMN priority TINYINT DEFAULT 0" --test-on-replica

# Produktiver Lauf mit interaktivem Steuerkanal über Unix Socket
gh-ost --host=db-primary.internal --database=magento --table=sales_order_grid --alter="ADD COLUMN priority TINYINT DEFAULT 0" --serve-socket-file=/tmp/gh-ost.sales_order_grid.sock --execute

6. Throttling und der interaktive Steuerkanal

gh-ost überwacht während der gesamten Migration kontinuierlich die Replikationsverzögerung auf allen konfigurierten Replicas. Überschreitet die Verzögerung den mit --max-lag-millis definierten Schwellenwert, drosselt gh-ost den Kopiervorgang automatisch, bis die Replicas wieder aufgeholt haben. Zusätzlich lässt sich über --nice-ratio ein bewusster Verlangsamungsfaktor konfigurieren, der auch ohne konkrete Lag-Überschreitung dauerhaft Rücksicht auf die reguläre Anwendungslast nimmt.

Über die genannte Unix-Socket-Schnittstelle lässt sich eine laufende Migration jederzeit manuell drosseln, mit dem Befehl throttle, oder wieder beschleunigen, mit no-throttle, ohne den Prozess neu starten zu müssen. Das ist besonders während unerwarteter Lastspitzen im Tagesgeschäft wertvoll, etwa bei einer plötzlichen Kampagne mit ungewöhnlich hohem Bestellaufkommen.

7. Der Cut-Over-Moment im Detail

Zum Abschluss der Migration bietet gh-ost zwei Cut-Over-Strategien. Der Standard, --cut-over=atomic, nutzt einen speziellen Lock-Mechanismus, der sicherstellt, dass während des Umschaltens keine Schreibzugriffe auf die alte Tabelle verloren gehen, indem kurzfristig alle Schreiboperationen blockiert werden, während die letzten ausstehenden Binlog-Ereignisse noch angewendet werden. Diese Blockade dauert typischerweise nur Sekundenbruchteile bis wenige Sekunden.

Die Alternative --cut-over=two-step arbeitet konservativer mit zwei getrennten Schritten und ist tolerant gegenüber bestimmten Verbindungsabbrüchen während des Umschaltens, benötigt dafür aber insgesamt etwas mehr Zeit. Für die meisten Magento-Migrationen ist der atomare Cut-Over die bevorzugte Wahl, solange die Netzwerkverbindung zwischen gh-ost-Prozess und Datenbankserver stabil ist.

8. Grenzen und Stolperfallen

Die wichtigste Einschränkung von gh-ost betrifft Fremdschlüssel: das Werkzeug unterstützt Tabellen mit Fremdschlüsselbeziehungen standardmäßig überhaupt nicht und bricht bei deren Erkennung ab, sofern nicht explizit --discard-foreign-keys gesetzt wird, was die Fremdschlüssel auf der neuen Tabelle vollständig entfernt. Bei stark vernetzten Magento-Tabellen mit vielen referenzierenden Fremdschlüsseln ist das ein erheblicher praktischer Unterschied zu pt-online-schema-change, das Fremdschlüssel zumindest konfigurierbar handhabt.

Weitere Einschränkungen: eine Tabelle benötigt zwingend einen Primärschlüssel oder mindestens einen eindeutigen, nicht-nullbaren Index als Grundlage für den Kopiervorgang, und bei extrem häufig geänderten Zeilen während der Migration kann sich die Restlaufzeit verlängern, weil dieselben Zeilen mehrfach über den Binärlog nachgezogen werden müssen. Auch Trigger auf der Originaltabelle, die selbst wieder DDL-relevante Nebeneffekte haben, sind mit dem Ghost-Ansatz nicht kompatibel.


-- Fremdschluessel-Erkennung vor der Migration pruefen
SELECT CONSTRAINT_NAME, TABLE_NAME, REFERENCED_TABLE_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_NAME = 'catalog_product_entity';

9. Wann gh-ost gegenüber pt-osc oder nativem DDL die richtige Wahl ist

gh-ost spielt seine Stärken vor allem bei Tabellen mit sehr hoher, konstanter Schreiblast aus, etwa quote_item, sales_order_grid oder benutzerdefinierten Log-Tabellen in stark frequentierten Magento-Shops, bei denen der Trigger-Overhead von pt-online-schema-change tatsächlich spürbar würde. Auch wenn eine feingranulare Steuerung über Throttling und ein besonders sicherer, getesteter Cut-Over-Mechanismus im Vordergrund stehen, ist gh-ost häufig die bevorzugte Wahl.

Bei Tabellen mit Fremdschlüsseln, bei denen ein vollständiges Entfernen der Referenzen keine Option ist, bleibt pt-online-schema-change dagegen häufig die praktikablere Lösung. Und für alle Operationen, die native ALGORITHM=INSTANT- oder INPLACE-Unterstützung besitzen und keine Kapazitätsprobleme mit dem Row-Log erwarten lassen, bleibt das eingebaute Online DDL von MySQL selbst weiterhin die einfachste und schnellste Option.

Kriterium gh-ost pt-online-schema-change
Change-Capture-Mechanismus Asynchrones Binlog-Streaming Synchrone Trigger
Schreib-Overhead auf der Originaltabelle Praktisch keiner Ein zusätzlicher Trigger-Aufwand pro Schreibzugriff
Fremdschlüssel-Unterstützung Nicht unterstützt, nur per Entfernen umgehbar Konfigurierbare Strategien verfügbar
Throttling Feingranular über Lag und interaktiven Steuerkanal Über Lag-Schwellenwert und Pause-Datei
Testbarkeit vor Produktiveinsatz Dedizierter --test-on-replica-Modus Nur Dry-Run ohne echten Replica-Test
Voraussetzung Binlog-Format binlog_format=ROW zwingend Keine besondere Anforderung

Mironsoft

Datenbank-Performance, Index-Tuning und Magento-DB-Optimierung

Magento-Shop, der an langsamen Datenbankabfragen leidet?

Wir analysieren MySQL-Datenbanken auf Performance-Bremsen, optimieren Indizes und Abfragen gezielt und richten Backup- und Replikationsstrategien ein, die im Ernstfall wirklich funktionieren.

Performance-Audit

Slow Query Log und Explain-Pläne systematisch auf Engpässe untersuchen.

Index-Optimierung

Indizes gezielt für die tatsächliche Abfragelast des Shops aufbauen.

Backup-Strategie

Zuverlässige Backup- und Restore-Prozesse für produktive Magento-Datenbanken einrichten.

10. Zusammenfassung

gh-ost: Triggerlose Migrationen

Binlog statt Trigger

gh-ost verhält sich wie ein Replica und liest Änderungen asynchron aus dem Binärlog statt über synchrone Trigger.

Kein Schreib-Overhead

Die Originaltabelle bleibt beim Schreiben unbeeinflusst, ideal für sehr schreibintensive Magento-Tabellen.

Fremdschlüssel-Lücke

Fremdschlüssel werden nicht unterstützt, nur über --discard-foreign-keys vollständig umgehbar.

Sicherer Workflow

Test-Run auf Replica, Dry-Run, feingranulares Throttling und ein atomarer Cut-Over minimieren das Risiko.

11. FAQ: gh-ost: Triggerlose Migrationen

1Warum unterstützt gh-ost keine Fremdschlüssel?
Der binlog-basierte Ansatz verfolgt Änderungen unabhängig von referenzieller Integrität, eine korrekte Übertragung von Fremdschlüsselbeziehungen auf die Ghost-Tabelle wäre technisch erheblich komplexer als beim trigger-basierten Ansatz. Die Entwickler haben sich bewusst gegen diese Komplexität entschieden.
2Was passiert, wenn die Netzwerkverbindung während der Migration abbricht?
gh-ost bricht die laufende Migration ab, die Ghost-Tabelle bleibt zurück und muss manuell entfernt werden. Die Originaltabelle bleibt davon vollständig unberührt, ein erneuter Start der Migration ist danach jederzeit möglich.
3Kann gh-ost auch ohne verfügbaren Replica genutzt werden?
Ja, mit dem Flag --allow-on-master liest gh-ost den Binärlog dann direkt vom Primärserver statt von einem Replica, was allerdings zusätzliche Leseoperationen auf dem produktiven Server erzeugt und deshalb nur bei fehlendem Replica sinnvoll ist.
4Wie stellt gh-ost sicher, dass die Ghost-Tabelle wirklich konsistent zur Original-Tabelle ist?
Der --test-on-replica-Modus vergleicht nach Abschluss der Testmigration automatisch Prüfsummen und Zeilenzahlen zwischen Original- und Ghost-Tabelle auf dem Replica, bevor überhaupt ein produktiver Lauf in Betracht gezogen wird.
5Unterstützt gh-ost auch MariaDB?
Grundsätzlich ja, solange die Zielinstanz zeilenbasierte Replikation im MySQL-kompatiblen Format bereitstellt, allerdings ist der primäre Entwicklungs- und Testfokus des Projekts auf MySQL und Percona Server ausgerichtet, weshalb Details je nach MariaDB-Version abweichen können.
6Wie lange dauert der Cut-Over-Moment typischerweise?
Beim atomaren Cut-Over meist deutlich unter einer Sekunde bis wenige Sekunden, abhängig von der Anzahl noch ausstehender Binlog-Ereignisse und der aktuellen Last auf der Zieltabelle zum Zeitpunkt des Umschaltens.
7Kann man eine laufende gh-ost-Migration jederzeit sicher abbrechen?
Ja, über die Unix-Socket-Schnittstelle mit dem Befehl panic oder schlicht durch Beenden des Prozesses. Die Originaltabelle bleibt in beiden Fällen unverändert, nur die Ghost-Tabelle und ihre Hilfsstrukturen müssen danach manuell aufgeräumt werden.
8Erzeugt gh-ost zusätzliche Last auf dem Datenbankserver während der Kopierphase?
Ja, in Form von Lesezugriffen für den Kopiervorgang und Schreibzugriffen für die Anwendung der Binlog-Ereignisse auf die Ghost-Tabelle, allerdings ohne den synchronen Trigger-Overhead, der bei jedem einzelnen Anwendungsschreibzugriff anfallen würde.
9Was bedeutet die Meldung über eskalierte Replikationsverzögerung während der Migration?
Sie zeigt an, dass ein überwachter Replica die konfigurierte Lag-Grenze überschritten hat und gh-ost den Kopiervorgang automatisch gedrosselt hat, um die Replikation nicht weiter zu belasten, bis der Replica wieder aufgeholt hat.
10Braucht man für gh-ost zusätzliche Serverressourcen neben MySQL selbst?
gh-ost läuft als eigenständiger externer Prozess, idealerweise auf einem separaten Host mit Netzwerkzugriff auf den Datenbankserver, um die CPU- und Speicherlast der Migration nicht zusätzlich auf dem Datenbankserver selbst zu erzeugen.