Gänsemigrationen für reibungslose Datenbankänderungen

Hallo, Kumpel!

Heute wollen wir darüber sprechen, was Datenbankmigrationen sind und warum sie so wichtig sind. In der heutigen Welt ist es keine Überraschung, dass Änderungen an einer Datenbank sorgfältig und gemäß eines spezifischen Prozesses durchgeführt werden sollten. Idealerweise sollten diese Schritte in unseren CI/CD-Pipeline integriert werden, damit alles automatisch abläuft.

Hier ist unsere Agenda:

  1. Was ist das Problem?
  2. Wie beheben wir es?
  3. Ein einfaches Beispiel
  4. Ein komplexeres Beispiel
  5. Empfehlungen
  6. Ergebnisse
  7. Schlussfolgerung

Was ist das Problem?

Wenn Ihr Team noch nie mit Datenbankmigrationen zu tun hatte und Sie nicht ganz sicher sind, warum sie benötigt werden, wollen wir das klären. Wenn Sie bereits die Grundlagen kennen, können Sie gerne vorspulen.

Hauptproblem

Wenn wir „geplante“ und „reibungslose“ Änderungen an der Datenbank vornehmen, müssen wir die Serviceverfügbarkeit aufrechterhalten und die SLA-Anforderungen erfüllen (damit Benutzer nicht unter Ausfallzeiten oder Verzögerungen leiden). Stellen Sie sich vor, Sie möchten den Spaltentyp in einer Tabelle mit 5 Millionen Benutzern ändern. Wenn Sie dies „frontal“ angehen (z.B. einfach ALTER TABLE ohne Vorbereitung ausführen), könnte die Tabelle für eine erhebliche Zeit gesperrt sein – und Ihre Benutzer wären ohne Service.

Um solche Kopfschmerzen zu vermeiden, befolgen Sie zwei Regeln:

  1. Führen Sie Migrationen so durch, dass die Tabelle nicht gesperrt wird (oder minimieren Sie zumindest die Sperrungen).
  2. Wenn Sie den Typ einer Spalte ändern müssen, ist es oft einfacher, zuerst eine neue Spalte mit dem korrekten Typ zu erstellen und dann die alte anschließend zu löschen.

Ein weiteres Problem: Versionskontrolle und Rollbacks

Manchmal müssen Sie eine Migration rückgängig machen.

Dies manuell zu tun – in die Produktionsdatenbank zu gehen und mit den Daten herumzuspielen – ist nicht nur riskant, sondern wahrscheinlich auch unmöglich, wenn Sie keinen direkten Zugriff haben. Hier kommen dedizierte Migrationswerkzeuge ins Spiel. Sie ermöglichen es Ihnen, Änderungen sauber anzuwenden und sie bei Bedarf zurückzunehmen.

Wie beheben wir das? Verwenden Sie die richtigen Tools

Jede Sprache und jedes Ökosystem hat seine eigenen Migrationswerkzeuge:

  • Für Java sind Liquibase oder Flyway gängig.
  • Für Go ist eine beliebte Wahl Goose (das werden wir uns hier ansehen).
  • Und so weiter.

Goose: Was es ist und warum es nützlich ist

Goose ist ein leichtgewichtiges Go-Dienstprogramm, das Ihnen hilft, Migrationen automatisch zu verwalten. Es bietet:

  • Einfachheit. Minimale Abhängigkeiten und eine transparente Dateistruktur für Migrationen.
  • Vielseitigkeit. Unterstützt verschiedene DB-Treiber (PostgreSQL, MySQL, SQLite usw.).
  • Flexibilität. Schreiben Sie Migrationen in SQL oder Go-Code.

Installation von Goose

Shell

 

So funktioniert es: Migrationsstruktur

Nach Vorgabe sucht Goose nach Migrationsdateien in db/migrations. Jede Migration folgt diesem Format:

Shell

 

  • NNN ist die Migrationsnummer (z. B. 001, 002 usw.).
  • Danach kann ein beliebiger beschreibender Name stehen, z. B. init_schema.
  • Die Erweiterung kann .sql oder .go sein.

Beispiel einer SQL-Migration

Datei: 001_init_schema.sql:

SQL

 

Unser erstes Beispiel

Ändern eines Spaltentyps (String → Int)

Angenommen, wir haben eine Tabelle users mit einer Spalte age vom Typ VARCHAR(255). Jetzt möchten wir sie in INTEGER ändern. So könnte die Migration aussehen (Datei 005_change_column_type.sql):

SQL

 

Was hier passiert:

  1. Up-Migration

    • Wir ändern die Spalte age in INTEGER. Die Klausel USING (age::INTEGER) sagt PostgreSQL, wie vorhandene Daten in den neuen Typ konvertiert werden sollen.
    • Beachten Sie, dass diese Migration fehlschlägt, wenn in age Daten enthalten sind, die nicht numerisch sind. In diesem Fall benötigen Sie eine komplexere Strategie (siehe unten).
  2. Abwärtsmigration

    • Wenn wir zurückrollen, wird age zu VARCHAR(255).
    • Wir verwenden erneut USING (age::TEXT), um von INTEGER zurück zu Text zu konvertieren.

Die zweiten und komplexen Fälle: Mehrstufige Migrationen

Wenn die Spalte age möglicherweise unordentliche Daten enthält (nicht nur Zahlen), ist es sicherer, dies in mehreren Schritten zu tun:

  1. Fügen Sie eine neue Spalte (age_int) vom Typ INTEGER hinzu.
  2. Kopieren Sie gültige Daten in die neue Spalte und behandeln oder entfernen Sie ungültige Einträge.
  3. Löschen Sie die alte Spalte.
SQL

 

Um ein ordnungsgemäßes Rollback zu ermöglichen, spiegelt der Abschnitt Down nur die Aktionen in umgekehrter Reihenfolge wider.

Automatisierung ist der Schlüssel

Um Zeit zu sparen, ist es wirklich praktisch, Migrationsbefehle zu einem Makefile (oder einem anderen Build-System) hinzuzufügen. Hier ist ein Beispiel-Makefile mit den wichtigsten Goose-Befehlen für PostgreSQL.

Angenommen:

  • Die DSN für die Datenbank lautet postgres://user:password@localhost:5432/dbname?sslmode=disable.
  • Die Migrationsdateien befinden sich in db/migrations.
Shell

 

Wie benutzt man es?

1. Erstellen Sie eine neue Migration (SQL-Datei). Dies erzeugt eine Datei db/migrations/002_add_orders_table.sql.

Shell

 

2. Führen Sie alle Migrationen aus. Goose wird eine schema_migrations Tabelle in Ihrer Datenbank erstellen (falls sie nicht bereits existiert) und alle neuen Migrationen in aufsteigender Reihenfolge anwenden.

Shell

 

3. Rollen Sie die letzte Migration zurück. Einfach die letzte.

Shell

 

4. Rollen Sie alle Migrationen zurück (Vorsicht bei der Produktion). Vollständiges Zurücksetzen.

Shell

 

5. Überprüfen Sie den Migrationsstatus.

Shell

 

Beispiel-Ausgabe:

Shell

 

Zusammenfassung

Durch die Verwendung von Migrationswerkzeugen und einem Makefile können wir:

  1. Direkten Zugriff auf die Produktionsdatenbank einschränken, Änderungen nur über Migrationen durchführen.
  2. Datenbankversionen leicht verfolgen und sie bei Bedarf zurückrollen.
  3. Eine einzige, konsistente Historie von Datenbankänderungen aufrechterhalten.
  4. „Sanfte“ Migrationen durchführen, die eine laufende Produktionsumgebung in einer Mikroservices-Welt nicht beeinträchtigen.
  5. Zusätzliche Validierung erhalten – jede Änderung wird einen PR- und Codeüberprüfungsprozess durchlaufen (sofern Sie diese Einstellungen haben).

Ein weiterer Vorteil ist, dass es einfach ist, all diese Befehle in Ihre CI/CD-Pipeline zu integrieren. Und denken Sie daran – Sicherheit geht vor. 

Zum Beispiel:

YAML

 

Abschluss und Tipps

Die Hauptideen sind ganz einfach:

  • Halten Sie Ihre Migrationen klein und häufig. Sie sind einfacher zu überprüfen, zu testen und bei Bedarf zurückzusetzen.
  • Verwenden Sie dasselbe Tool in allen Umgebungen, damit Entwicklung, Test und Produktion synchron sind.
  • Integrieren Sie Migrationen in CI/CD, damit Sie nicht von einer Person abhängig sind, die sie manuell ausführt.

Auf diese Weise haben Sie einen zuverlässigen und kontrollierten Prozess zur Änderung Ihrer Datenbankstruktur – einen, der die Produktion nicht beeinträchtigt und es Ihnen ermöglicht, schnell zu reagieren, wenn etwas schief geht. 

Viel Erfolg mit Ihren Migrationen!

Vielen Dank fürs Lesen!

Source:
https://dzone.com/articles/goose-as-crucial-tool-for-your-service