¿Cómo ejecutar migraciones de bases de datos de forma segura con varias instancias de aplicación?

10

Tenemos una aplicación que tiene una combinación de migraciones de bases de datos rápidas (<1 segundo) y lentas (> 30 segundos). En este momento, estamos ejecutando migraciones de bases de datos como parte de CI, pero nuestra herramienta de CI tiene que conocer todas las cadenas de conexión de la base de datos para nuestra aplicación (en múltiples entornos), lo cual no es ideal. Queremos cambiar este proceso para que la aplicación ejecute sus propias migraciones de bases de datos cuando se inicie.

Aquí está la situación:

Tenemos varias instancias de esta aplicación, alrededor de 5 en producción. Vamos a llamarlos node1, ..., node5. Cada aplicación se conecta a una única instancia de SQL Server, y no estamos usando implementaciones continuas (todas las aplicaciones se implementan simultáneamente hasta donde yo sé)

Problema: digamos que tenemos una migración de larga duración. En este caso, node1comienza, luego comienza a ejecutar la migración. Ahora, node4comienza, y la migración de larga duración aún no ha terminado, por lo que node4también comienza a ejecutar la migración -> posible corrupción de datos? ¿Cómo evitarías este problema o es el problema lo suficientemente importante como para preocuparte?

Estaba pensando en resolver este problema con un bloqueo distribuido (usando etcdo algo por el estilo). Básicamente, todas las aplicaciones intentan adquirir el bloqueo, solo una de ellas lo consigue y ejecuta las migraciones, luego se desbloquea. Cuando el resto de las aplicaciones se inician y entran en la sección crítica, todas las migraciones ya se han ejecutado, por lo que el script de migración acaba de salir.

Sin embargo, mi instinto dice "esto es excesivo, debe haber una solución más simple", así que pensé en preguntar aquí para ver si alguien más tiene mejores ideas.

Ben
fuente
1
¿Qué tal usar una tabla de "estado de migración" como su bloqueo global / distribuido? La fila única indicaría si una migración está actualmente activa y posiblemente qué migración se ejecutó por última vez.
Bart van Ingen Schenau
¿Necesita implementar sus aplicaciones de forma asincrónica?
Ben

Respuestas:

4

Como mencionó el servidor SQL: de acuerdo con esta publicación anterior de DBA.SE , los cambios de esquema pueden (y deben) ponerse en transacciones. Esto le brinda la capacidad de diseñar sus migraciones como cualquier otra forma de escritura simultánea en su base de datos: inicia una transacción y, cuando falla, la revierte. Eso evita al menos algunos de los peores escenarios de corrupción de la base de datos (aunque las transacciones por sí solas no evitarán la pérdida de datos cuando hay pasos de migración destructivos como eliminar una columna o tabla).

Hasta ahora, estoy seguro de que también necesitará alguna migrationstabla donde se registren las migraciones ya aplicadas, por lo que un proceso de solicitud puede verificar si una migración específica ya se aplicó o no. Luego utilice "SELECCIONAR PARA ACTUALIZAR" para implementar sus migraciones de esta manera (pseudocódigo):

  • Comience una transacción
  • SELECT FROM Migrations FOR UPDATE WHERE MigrationLabel='MyMigration42'
  • Si la declaración anterior devuelve un valor, finalice la transacción
  • aplique la migración (retroceda si falla, registre la falla y finalice la transacción)
  • INSERT 'MyMigration42' INTO Migrations(MigrationLabel)
  • finalizar la transacción

Eso construye el mecanismo de bloqueo directamente en la prueba "fue la migración ya aplicada" .

Tenga en cuenta que este diseño permitirá, en teoría, dejar que sus pasos de migración no sean conscientes de qué aplicación realmente lo aplica; puede ser posible que el paso 1 se aplique por la aplicación1, el paso 2 por la aplicación2, el paso 3 por la aplicación 3, el paso 4 por la aplicación1 de nuevo, y así sucesivamente. Sin embargo, también es una buena idea no aplicar migraciones siempre que otras instancias de aplicaciones estén en uso. La implementación paralela, como se mencionó en su pregunta, ya puede tener en cuenta esta restricción.

Doc Brown
fuente
1

Quizás pueda encontrar una biblioteca que admita la migración de bases de datos con múltiples nodos.

Conozco dos bibliotecas en el mundo de Java, ambas admiten lo que necesitas:

  • Liquibase : de sus preguntas frecuentes : Liquibase utiliza un sistema de bloqueo distribuido para permitir que solo un proceso actualice la base de datos a la vez. Los otros procesos simplemente esperarán hasta que se libere el bloqueo.
  • Flyway : desde su página de descarga : seguro para múltiples nodos en paralelo ✓

Probablemente hay otras herramientas para Java y otros lenguajes también.


Si no puede (o no quiere) usar dicha herramienta, una tabla se puede usar como un bloqueo o incluso como un registro de migración, consulte la respuesta de Doc Browns para ver un ejemplo.

siegi
fuente