Implementación de tiempo de inactividad cero: esquema de transición de base de datos

14

Lograr la implementación del tiempo de inactividad cero tocó el mismo problema, pero necesito algunos consejos sobre una estrategia que estoy considerando.

Contexto

Una aplicación basada en la web con Apache / PHP para el procesamiento del lado del servidor y MySQL DB / sistema de archivos para la persistencia.

Actualmente estamos construyendo la infraestructura. Todo el hardware de red tendrá redundancia y todos los cables de red principales se utilizarán en pares unidos para tolerancia a fallas. Los servidores se están configurando como pares de alta disponibilidad para la tolerancia a fallos de hardware y se equilibrarán en carga tanto para la tolerancia a fallos de la máquina virtual como para el rendimiento general.

Es mi intención que podamos aplicar actualizaciones a la aplicación sin ningún tiempo de inactividad. Me he esforzado mucho al diseñar la infraestructura para garantizar que pueda proporcionar un tiempo de actividad del 100%; Sería extremadamente decepcionante tener un tiempo de inactividad de 10-15 minutos cada vez que se aplica una actualización. Esto es particularmente significativo ya que pretendemos tener un ciclo de liberación muy rápido (a veces puede alcanzar una o más emisiones por día.

Topología de la red

Este es un resumen de la red:

                      Load Balancer
             |----------------------------|
              /       /         \       \  
             /       /           \       \ 
 | Web Server |  DB Server | Web Server |  DB Server |
 |-------------------------|-------------------------|
 |   Host-1   |   Host-2   |   Host-1   |   Host-2   |
 |-------------------------|-------------------------|
            Node A        \ /        Node B
              |            /            |
              |           / \           |
   |---------------------|   |---------------------|
           Switch 1                  Switch 2

   And onward to VRRP enabled routers and the internet

Nota: los servidores de base de datos utilizan la replicación maestro-maestro

Estrategia sugerida

Para lograr esto, actualmente estoy pensando en dividir los scripts de actualización del esquema DB en dos partes. La actualización se vería así:

  1. El servidor web en el nodo A se desconecta; el tráfico continúa siendo procesado por el servidor web en el nodo B.
  2. Los cambios de esquema de transición se aplican a los servidores de base de datos
  3. Servidor web Se actualiza una base de código, se borran las memorias caché y se toman otras acciones de actualización.
  4. El servidor web A se pone en línea y el servidor web B se desconecta.
  5. La base de código del servidor web B se actualiza, los cachés se borran y se toman otras acciones de actualización.
  6. El servidor web B se pone en línea.
  7. Los cambios finales del esquema se aplican a la base de datos

El 'esquema de transición' se diseñaría para establecer una base de datos compatible con versiones cruzadas. Esto utilizaría principalmente vistas de tabla que simulan el esquema de la versión anterior, mientras que la tabla misma se modificaría al nuevo esquema. Esto permite que la versión anterior interactúe con el DB de manera normal. Los nombres de las tablas incluirían números de versión de esquema para garantizar que no haya ninguna confusión sobre a qué tabla escribir.

'Esquema final' eliminaría la compatibilidad con versiones anteriores y ordenaría el esquema.

Pregunta

En resumen, ¿funcionará esto?

más específicamente:

  1. ¿Habrá problemas debido al potencial de escrituras concurrentes en el punto específico del cambio de esquema de transición? ¿Hay alguna manera de asegurarse de que el grupo de consultas que modifican la tabla y crean la vista compatible con versiones anteriores se ejecutan consecutivamente? es decir, con cualquier otra consulta retenida en el búfer hasta que se completen los cambios de esquema, que generalmente solo serán milisegundos.

  2. ¿Existen métodos más simples que brinden este grado de estabilidad y que también permitan actualizaciones sin tiempo de inactividad? También se prefiere evitar la estrategia de esquema 'evolutivo' ya que no deseo quedar bloqueado en la compatibilidad con esquemas anteriores.

Marvin
fuente

Respuestas:

4

Parece que lo que realmente está buscando no es tanto Alta disponibilidad como necesitaría Disponibilidad continua .

Esencialmente, su plan funcionará, pero parece haber notado que la falla principal en su configuración es que los cambios en el esquema de la base de datos en una versión podrían provocar el tiempo de inactividad o la falla del nodo aún disponible para funcionar correctamente. El enfoque de disponibilidad continua resuelve esto creando esencialmente una serie de entornos de producción.

Producción uno

Este entorno es su versión actual en vivo del software que utilizan los usuarios. Tiene sus propios servidores web, servidores de aplicaciones y servidores de bases de datos y espacios de tabla. Funciona independientemente de cualquier otro entorno. El Load Balancer que posee el punto final de resolución de dominio para estos servicios está apuntando actualmente a estos servidores web.

Producción dos

Esto es básicamente un entorno de puesta en escena de lanzamiento que es idéntico a Production One. Puede realizar sus actualizaciones de lanzamiento aquí y hacer sus pruebas de cordura antes de su evento de lanzamiento en vivo. Esto también le permite realizar de manera segura los cambios de su base de datos en este entorno. Load Balancer no apunta a este entorno actualmente.

DR de producción

Este es otro duplicado en un centro de datos separado que se encuentra en una región diferente del mundo. Esto le permite fallar en caso de evento catastrófico al hacer un cambio de DNS en Load Balancer.

Ir a vivir

Este evento esencialmente está actualizando el registro DNS para pasar a la producción dos desde la producción uno o viceversa. Esto demora un tiempo en propagarse a través de los servidores DNS del mundo, por lo que deja ambos entornos funcionando por un tiempo. Algunos usuarios PUEDEN estar trabajando en sesiones existentes en la versión anterior de su software. La mayoría de los usuarios establecerán nuevas sesiones en la versión actualizada de su software.

Migración de datos

El único inconveniente aquí es que no todos los datos durante esa ventana están disponibles para todos los usuarios en ese momento. Hay datos de usuario claramente importantes en la base de datos de la versión anterior que ahora deben migrarse de forma segura al nuevo esquema de base de datos. Esto se puede lograr con un script de exportación y migración de datos bien probado o un trabajo por lotes o un proceso ETL similar.

Conclusión

Una vez que haya completado completamente su evento de lanzamiento, Production Two es ahora su principal y comienza a trabajar en la instalación del próximo lanzamiento en Production One para el próximo ciclo de implementación.

Inconvenientes

Esta es una configuración de entorno compleja y requiere una gran cantidad de recursos del sistema, a menudo multiplicada por dos o tres veces los recursos del sistema para funcionar correctamente. Operar de esta manera puede ser costoso, especialmente si tiene sistemas de uso intensivo muy grandes.

árbol de arce
fuente
Entonces, si he entendido correctamente, sugiere que en lugar de un cambio de esquema de base de datos 'transicional' que se aplique mientras el Db todavía está en uso, Db-A se mantiene en línea con el esquema anterior mientras Db-B se actualiza al nuevo esquema. Cuando la actualización está lista para su lanzamiento, los servidores web se cambian y los datos que se escribieron en Db A mientras se preparaba la actualización se migran a Db B (presumiblemente al aplicar todos los cambios después de una marca de tiempo específica).
Marvin
@PeterScott Lo tienes. Solo tenga en cuenta que no desea ejecutar el script hasta que esté seguro de que todas las sesiones activas hayan terminado en el sistema anterior y que haya transcurrido el tiempo suficiente para que todas las memorias caché DNS se hayan actualizado a la nueva dirección CNAME o IP.
maple_shaft
1
Debería estar bien en ambos puntos; las sesiones se mantienen en el Db en lugar del almacenamiento del servidor para evitar que las sesiones estén vinculadas a máquinas virtuales específicas y actualmente tengo la intención de tratar de usar un equilibrador de carga no basado en DNS. No tendré redundancia a nivel de centro de datos, pero eso puede esperar aproximadamente un año después del lanzamiento de la aplicación.
Marvin
2

Tu estrategia es sólida. Solo ofrecería considerar expandir el "Esquema de transición" en un conjunto completo de "tablas de transacciones".

Con las tablas de transacciones, los SELECT (consultas) se realizan contra las tablas normalizadas para garantizar la corrección. Pero todas las INSERTAS, ACTUALIZACIONES y DELETAS de la base de datos siempre se escriben en las tablas de transacciones desnormalizadas.

Luego, un proceso concurrente separado aplica esos cambios (quizás usando procedimientos almacenados) a las tablas normalizadas según las reglas de negocio y los requisitos de esquema establecidos.

La mayoría de las veces, esto sería prácticamente instantáneo. Pero separar las acciones le permite al sistema acomodar la actividad excesiva y los retrasos en la actualización del esquema.

Durante los cambios de esquema en la base de datos (B), las actualizaciones de datos en la base de datos activa (A) irían a sus tablas de transacciones y se aplicarían inmediatamente a sus tablas normalizadas.

Al recuperar la base de datos (B), las transacciones de (A) se aplicarían a ella escribiéndolas en las tablas de transacciones de (B). Una vez que se hace esa parte, (A) podría ser derribado y los cambios de esquema aplicados allí. (B) terminaría de aplicar las transacciones de (A) mientras también manejaba sus transacciones en vivo que se pondrían en cola como lo hizo (A) y los "en vivo" se aplicarían de la misma manera cuando (A) volviera a subir.

Una fila de la tabla de transacciones podría parecerse a ...

| ROWID | TRANSNR | DB | TABLE | SQL STATEMENT
    0        0       A    Name   INSERT INTO Name ...
    1        0       A    Addr   INSERT INTO Addr ...
    2        0       A    Phone  INSERT INTO Phone ...
    3        1       A    Stats   UPDATE Stats SET NrOfUsers=...

Las "tablas" de transacciones podrían ser filas en una base de datos NoSQL separada o incluso archivos secuenciales, según los requisitos de rendimiento. Una ventaja es que la codificación de la aplicación (sitio web en este caso) se vuelve un poco más simple ya que solo escribe en las tablas de transacciones.

La idea sigue los mismos principios que la contabilidad de doble entrada, y por razones similares.

Las tablas de transacciones son análogas a un "diario" de contabilidad. Las tablas totalmente normalizadas son análogas a un "libro de contabilidad" de contabilidad y cada tabla es algo así como una "cuenta" de contabilidad.

En la contabilidad, cada transacción obtiene dos entradas en el diario. Uno para la cuenta contable "debitada" y el otro para la cuenta "acreditada".

En un RDBMS, un "diario" (tabla de transacciones) obtiene una entrada para cada tabla normalizada a ser modificada por esa transacción.

La columna de base de datos en la ilustración de la tabla anterior indica en qué base de datos se originó la transacción, lo que permite que las filas en cola de la otra base de datos se filtren y no se vuelvan a aplicar cuando la segunda base de datos se vuelva a activar.

DocSalvager
fuente
1
Me gusta la comparación con la contabilidad. Entonces, si he entendido, las tablas de transacciones me permiten colocar un retraso muy pequeño en la escritura de datos en una tabla normalizada particular para que pueda aplicar todos los cambios de esquema sin riesgo de interrupción a mitad de camino. Luego, con el esquema de la tabla actualizado, ¿puedo reanudar el proceso que aplica las transacciones denormalizadas a las tablas normalizadas (este proceso es capaz de mapear las consultas de datos del esquema antiguo al nuevo esquema)?
Marvin el
1
Si. Modificaría los procedimientos almacenados de mapeo (o lo que sea) para acomodar los datos antiguos y nuevos. Las nuevas columnas NOT-NULL pueden rellenarse a partir de datos antiguos con un código que significa "solicitar esto en la actualización del usuario". Las columnas a dividir (es decir, NOMBRE COMPLETO en PRIMERO y ÚLTIMO) necesitarían algún algoritmo. Recomiendo agregar 1 o más columnas "similares a comentarios" a las tablas para los nuevos requisitos de biz que surjan. Si no lo hace, le garantizo que los usuarios se apropiarán de otras columnas para ese propósito y la fijación de los datos será casi imposible.
DocSalvager
¿Cómo evitaría que las consultas SELECT estructuradas para el antiguo esquema se apliquen al nuevo esquema? Podría usar crear una vista de tabla y cambiar el nombre de la tabla de esquema (con un número de versión de esquema) pero esto aún sería problemático mientras se aplican los cambios de esquema, ya que se aplican directamente a la tabla normalizada.
Marvin el
1
Cuando agrega una tabla, columna o cualquier otra cosa a un RDBMS, en realidad solo está agregando filas a un conjunto de tablas internas en las que solo puede escribir el motor RDBMS. Los DBA administran la base de datos al consultarlos a través de VIEW. Dado que Oracle, IBM, MS, etc. son los expertos y dicen que esta es la mejor manera, parece que deberíamos seguir su ejemplo. Cree un conjunto de VIEWs para cada versión de la aplicación. Puede modelarlos después de las tablas (generalmente bastante desnormalizadas) que los desarrolladores quieren que cree para que pueda normalizar adecuadamente para evitar datos corruptos.
DocSalvager
Gracias. Tendré que pensar en esto. Estoy creando una capa ORM en la aplicación que elimina completamente toda la lógica de persistencia de estado del dominio principal; estando más basado en la programación del lado del servidor, tiendo a resolver los problemas más desde ese lado que desde el lado de la administración de la base de datos. Usando mi estrategia actual, el Db sería bastante plano con el ORM administrando activamente las tablas en bruto. Agregar vistas de tabla y, posiblemente, un registro de transacciones agrega una mayor complejidad al ORM, pero también permite que se admitan múltiples versiones de esquema sin fragmentación de datos.
Marvin