Come eseguire in sicurezza migrazioni di database con più istanze di app?


10

Abbiamo un'applicazione che ha una combinazione di migrazioni di database rapide (<1 secondo) e lente (> 30 secondi). In questo momento, stiamo eseguendo migrazioni di database come parte di CI, ma poi il nostro strumento di CI deve conoscere tutte le stringhe di connessione al database per la nostra app (su più ambienti) che non è l'ideale. Vogliamo modificare questo processo in modo che l'applicazione esegua le proprie migrazioni del database all'avvio.

Ecco la situazione:

Abbiamo più istanze di questa applicazione - circa 5 in produzione. Chiamiamoli node1, ..., node5. Ogni app si connette a una singola istanza di SQL Server e non utilizziamo distribuzioni in sequenza (per quanto ne so tutte le app vengono distribuite contemporaneamente)

Problema: supponiamo di avere una migrazione di lunga durata. In questo caso, node1avvia, quindi inizia l'esecuzione della migrazione. Ora, node4inizia e la migrazione a lungo termine non è ancora terminata, quindi node4inizia anche a eseguire la migrazione -> possibile corruzione dei dati? Come prevenire questo problema o il problema è ancora abbastanza importante di cui preoccuparsi?

Stavo pensando di risolvere questo problema con un blocco distribuito (usando etcdo qualcosa del genere). Fondamentalmente, tutte le app cercano di acquisire il blocco, solo uno di loro lo ottiene ed esegue le migrazioni, quindi si sblocca. Quando le altre app si avviano ed entrano nella sezione critica, tutte le migrazioni sono già state eseguite, quindi lo script di migrazione si chiude.

Tuttavia, il mio istinto sta dicendo "questo è eccessivo, ci deve essere una soluzione più semplice", quindi ho pensato che avrei chiesto qui per vedere se qualcun altro ha idee migliori.


1
Che ne dite di usare una tabella "stato della migrazione" come blocco globale / distribuito? La singola riga indica se una migrazione è attualmente attiva e, eventualmente, quale migrazione è stata eseguita per ultima.
Bart van Ingen Schenau,

Devi distribuire le tue app in modo asincrono?
Ben

Risposte:


4

Da quando hai citato il server SQL: secondo questo precedente post DBA.SE , le modifiche allo schema possono (e dovrebbero) essere inserite nelle transazioni. Ciò ti dà la possibilità di progettare le tue migrazioni proprio come qualsiasi altra forma di scritture simultanee sul tuo DB: avvii una transazione e quando fallisce la ripristini. Ciò impedisce almeno alcuni dei peggiori scenari di corruzione del database (anche se le transazioni da sole non impediranno la perdita di dati in caso di passaggi di migrazione distruttivi come l'eliminazione di una colonna o di una tabella).

Finora, sono sicuro che avrai bisogno anche di una migrationstabella in cui sono registrate le migrazioni già applicate, quindi un processo di applicazione può verificare se una specifica migrazione è già stata applicata o meno. Quindi utilizzare "SELEZIONA PER AGGIORNARE" per implementare le migrazioni in questo modo (pseudo codice):

  • Inizia una transazione
  • SELECT FROM Migrations FOR UPDATE WHERE MigrationLabel='MyMigration42'
  • se la precedente istruzione restituisce un valore, termina la transazione
  • applica la migrazione (ripristina se fallisce, registra l'errore e termina la transazione)
  • INSERT 'MyMigration42' INTO Migrations(MigrationLabel)
  • terminare la transazione

Ciò crea il meccanismo di blocco direttamente nel test "era la migrazione già applicata" .

Nota che questo progetto consentirà - in teoria - di far ignorare i passaggi della migrazione a quale applicazione effettivamente lo applica - è possibile che il passaggio 1 sia applicato dall'app1, il passaggio 2 dall'app2, il passaggio 3 dall'app 3, il passaggio 4 dall'app1 di nuovo, e così via. Tuttavia, è anche consigliabile non applicare le migrazioni finché sono in uso altre istanze di app. La distribuzione parallela, come menzionato nella domanda, potrebbe già occuparsi di questo vincolo.


1

Forse puoi trovare una libreria che supporta la migrazione del database con più nodi.

Conosco due librerie nel mondo Java, entrambe supportano ciò di cui hai bisogno:

  • Liquibase : dalle loro FAQ : Liquibase utilizza un sistema di blocco distribuito per consentire a un solo processo di aggiornare il database alla volta. Gli altri processi aspetteranno semplicemente fino al rilascio del blocco.
  • Flyway : dalla loro pagina di download : sicuro per più nodi in parallelo ✓

Probabilmente ci sono altri strumenti per Java e altre lingue.


Se non si è in grado (o non si desidera) utilizzare tale strumento, una tabella può essere utilizzata come blocco o persino come registro di migrazione, vedere la risposta di Doc Browns per un esempio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.