Wie können Datenbankmigrationen mit mehreren App-Instanzen sicher ausgeführt werden?

10

Wir haben eine Anwendung, die eine Mischung aus schnellen (<1 Sekunde) und langsamen Datenbankmigrationen (> 30 Sekunden) bietet. Momentan führen wir Datenbankmigrationen als Teil von CI durch, aber dann muss unser CI-Tool alle Datenbankverbindungszeichenfolgen für unsere App (in mehreren Umgebungen) kennen, was nicht ideal ist. Wir möchten diesen Prozess so ändern, dass die Anwendung beim Start ihre eigenen Datenbankmigrationen ausführt.

Hier ist die Situation:

Wir haben mehrere Instanzen dieser Anwendung - ungefähr 5 in der Produktion. Nennen wir sie node1, ..., node5. Jede App stellt eine Verbindung zu einer einzelnen SQL Server-Instanz her, und wir verwenden keine fortlaufenden Bereitstellungen (soweit ich weiß, werden alle Apps gleichzeitig bereitgestellt).

Problem: Angenommen, wir haben eine lange laufende Migration. In diesem Fall wird node1die Migration gestartet und anschließend ausgeführt. Startet jetzt node4und die lang laufende Migration ist noch nicht abgeschlossen. Startet also node4auch die Migration -> mögliche Datenbeschädigung? Wie würden Sie dieses Problem verhindern oder ist das Problem überhaupt wichtig genug, um sich Sorgen zu machen?

Ich dachte daran, dieses Problem mit einer verteilten Sperre zu lösen (mit etcdoder etwas in dieser Richtung). Grundsätzlich versuchen alle Apps, die Sperre zu erlangen. Nur eine von ihnen erhält sie und führt die Migrationen aus und entsperrt sie dann. Wenn der Rest der Apps gestartet wird und in den kritischen Bereich wechselt, wurden bereits alle Migrationen ausgeführt, sodass das Migrationsskript nur beendet wird.

Mein Bauch sagt jedoch: "Das ist übertrieben, es muss eine einfachere Lösung geben." Also dachte ich mir, ich würde hier fragen, ob jemand andere bessere Ideen hat.

Ben
quelle
1
Wie wäre es mit einer "Migrationsstatus" -Tabelle als globale / verteilte Sperre? Die einzelne Zeile zeigt an, ob eine Migration derzeit aktiv ist und möglicherweise welche Migration zuletzt ausgeführt wurde.
Bart van Ingen Schenau
Müssen Sie Ihre Apps asynchron bereitstellen?
Ben

Antworten:

4

Da Sie SQL Server erwähnt haben: Gemäß diesem früheren DBA.SE-Beitrag können (und sollten) Schemaänderungen in Transaktionen übernommen werden. Auf diese Weise können Sie Ihre Migrationen wie jede andere Form von gleichzeitigen Schreibvorgängen in Ihre Datenbank gestalten. Sie starten eine Transaktion und setzen sie zurück, wenn sie fehlschlägt. Dies verhindert zumindest einige der schlimmsten Datenbankbeschädigungsszenarien (obwohl Transaktionen allein keinen Datenverlust verhindern, wenn destruktive Migrationsschritte wie das Löschen einer Spalte oder Tabelle ausgeführt werden).

Bisher benötigen Sie sicher auch eine migrationsTabelle, in der bereits angewendete Migrationen registriert sind, damit ein Anwendungsprozess prüfen kann, ob eine bestimmte Migration bereits angewendet wurde oder nicht. Verwenden Sie dann "SELECT FOR UPDATE", um Ihre Migrationen wie folgt zu implementieren (Pseudocode):

  • Starten Sie eine Transaktion
  • SELECT FROM Migrations FOR UPDATE WHERE MigrationLabel='MyMigration42'
  • Wenn die vorherige Anweisung einen Wert zurückgibt, beenden Sie die Transaktion
  • Wenden Sie die Migration an (rollen Sie zurück, wenn dies fehlschlägt, protokollieren Sie den Fehler und beenden Sie die Transaktion).
  • INSERT 'MyMigration42' INTO Migrations(MigrationLabel)
  • Beenden Sie die Transaktion

Dadurch wird der Sperrmechanismus direkt in den Test " Wurde die Migration bereits angewendet" integriert .

Beachten Sie, dass dieses Design theoretisch ermöglicht, dass Ihre Migrationsschritte nicht wissen, welche Anwendung sie tatsächlich anwendet. Möglicherweise wird Schritt 1 von App1, Schritt 2 von App2, Schritt 3 von App 3, Schritt 4 von App1 angewendet wieder und so weiter. Es ist jedoch auch eine gute Idee, keine Migrationen anzuwenden, solange andere App-Instanzen verwendet werden. Die parallele Bereitstellung, wie in Ihrer Frage erwähnt, kann diese Einschränkung bereits berücksichtigen.

Doc Brown
quelle
1

Möglicherweise finden Sie eine Bibliothek, die die Datenbankmigration mit mehreren Knoten unterstützt.

Ich kenne zwei Bibliotheken in der Java-Welt, die beide unterstützen, was Sie brauchen:

  • Liquibase : Aus ihrer FAQ : Liquibase nutzt ein verteilte Verriegelungssystem mit nur einem Prozess erlauben , die Datenbank zu einem Zeitpunkt , zu aktualisieren. Die anderen Prozesse warten einfach, bis die Sperre aufgehoben wurde.
  • Flyway : Von ihrer Download-Seite : Sicher für mehrere Knoten gleichzeitig ✓

Es gibt wahrscheinlich auch andere Tools für Java und andere Sprachen.


Wenn Sie ein solches Tool nicht verwenden können (oder möchten), kann eine Tabelle als Sperre oder sogar als Migrationsprotokoll verwendet werden. Ein Beispiel finden Sie in der Antwort von Doc Browns .

siegi
quelle