Copia de seguridad de una base de datos MySQL a través de instantáneas ZFS

12

He encontrado varios sitios que hablan de hacer exactamente esto, pero me faltan algunos detalles importantes. Los pasos generales son

  • correr FLUSH TABLES WITH READ LOCK
  • Tome la instantánea de ZFS
  • correr UNLOCK TABLES

Varias fuentes informan que InnoDB, que estoy usando, en realidad no respeta a FLUSH. El manual de usuario de MySQL señala que hay una FLUSH TABLES...FOR EXPORTvariante para usar con InnoDB, pero eso requiere especificar cada tabla individualmente, en lugar de hacer una copia de seguridad de toda la base de datos. Prefiero evitar especificar cada tabla individualmente porque hay una posibilidad decente de que la lista de tablas no esté sincronizada con las tablas que realmente existen.

El otro problema que tengo es que planeé hacer algo así mysql -h"$HOST" -u"$USERNAME" -p"$PASSWORD" --execute="FLUSH TABLES WITH READ LOCK". Sin embargo, esto cierra el bloqueo inmediatamente después de que finaliza la sesión. Esto tiene sentido, pero también es bastante molesto ya que necesito mantener el bloqueo de lectura cuando tomo mi instantánea.

Mi otra idea es hacer una copia de seguridad en caliente usando una herramienta como Percona XtraBackup y tomar instantáneas de la copia de seguridad, pero preferiría no pagar el costo de escribir todos mis datos en una segunda ubicación solo para capturarla.

Andy Shulman
fuente
¿Por qué tener una lista estática de tablas? Seguramente puede generar una lista dinámicamente en tiempo de ejecución.
EEAA
1
¿Está la base de datos en una VM o en el metal desnudo? ¿El almacenamiento está incluso en la misma máquina?
Michael Hampton
EEAA, bastante justo.
Andy Shulman
Michael, la base de datos y el cuadro ZFS son máquinas diferentes, pero ninguno está virtualizado.
Andy Shulman
@AndyShulman Creo que deberías explicar el diseño un poco mejor. Esto no tiene sentido.
ewwhite

Respuestas:

4

Si solo usa InnoDB para todas las tablas y se establece innodb_flush_log_at_trx_commiten:

  • 1 (el contenido del búfer de registro de InnoDB se escribe en el archivo de registro en cada confirmación de transacción y el archivo de registro se vacía en el disco) o,
  • 2 (el contenido del búfer de registro de InnoDB se escribe en el archivo de registro después de cada confirmación de transacción y el archivo de registro se vacía en el disco aproximadamente una vez por segundo),

entonces no necesita FLUSH TABLES antes de hacer una instantánea, simplemente ejecute la instantánea ZFS directamente. InnoDB puede recuperar datos de registros de confirmación de transacciones sin pérdida de datos.

Ref: https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit

Gea-Suan Lin
fuente
Con el diccionario de datos introducido en MySQL 8, incluso las operaciones DDL (modificación de esquema) ahora son atómicas. Antes de eso, las operaciones DDL durante una instantánea del sistema de archivos podrían dar resultados parcialmente comprometidos (es decir, corruptos).
bernie
13

Necesita un bloqueo completo de la base de datos para hacer una copia de seguridad de una (la mayoría) de las bases de datos de manera consistente.

El manual https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html dice FLUSH TABLES WITH READ LOCK es correcto para las instantáneas de ZFS específicamente.

Hacer copias de seguridad utilizando una instantánea del sistema de archivos

Si está utilizando un sistema de archivos Veritas, puede hacer una copia de seguridad como esta:

  1. Desde un programa cliente, ejecutar FLUSH TABLES WITH READ LOCK.
  2. Desde otro shell, ejecute la vxfsinstantánea de montaje .
  3. Desde el primer cliente, ejecute UNLOCK TABLES.
  4. Copie archivos de la instantánea.
  5. Desmonta la instantánea.

Capacidades de instantáneas similares pueden estar disponibles en otros sistemas de archivos, como LVM o ZFS.

Es un poco ridículo que dejaron el hecho de que usted necesita FLUSH TABLES table_a, table_b, table_c FOR EXPORTpara InnoDB de estas instrucciones. También es estúpido tener que especificar cada tabla de esa manera. Pero como dice EEAA, puede generar una lista de tablas a medida que comienza la copia de seguridad con bastante facilidad.

En cuanto a mantener el bloqueo, debe mantener activa la conexión db mientras realiza la instantánea

En general, usaría algo como Perl u otro lenguaje de programación que pueda conectarse, bloquear la base de datos y, mientras mantengo la conexión de la base de datos, tomar la instantánea, luego desbloquear y desconectar. No es complejo Apostaría a que existen herramientas que ya hacen esto, pero escribir una es fácil.

Digo fácil, no complejo, etc. algunas veces. Supongo que tienes algo de programación básica o buenas habilidades de secuencias de comandos.

Ryan Babchishin
fuente
Tenía la esperanza de mantener una secuencia de comandos tan conceptualmente simple en Bash, pero tienes razón al cambiar de idioma lo hace mucho más fácil. Puede que esté leyendo su respuesta de forma incorrecta, pero parece que está diciendo que necesito ejecutar ambas FLUSH TABLES WITH READ LOCKy luego FLUSH TABLES...FOR EXPORT, mientras que mi lectura del manual de MySQL dice que solo una debería ser necesaria.
Andy Shulman
Lo siento, no estaba claro. Solo estoy siguiendo el manual y dice dos cosas diferentes. Supongo que estás en lo correcto y solo necesitas lo posterior. Pero todas las tablas deben estar bloqueadas en un solo comando.
Ryan Babchishin
1
Dado que la documentación no es muy clara, toda la base de datos debe estar bloqueada y que se debe mantener una conexión de base de datos mientras se toma la instantánea, parece más fácil simplemente cerrar la base de datos, hacer una copia de seguridad y reiniciar eso.
Andrew Henle
2
@andrew suspiro ... lo entiendo. Pero eso será lento, hará que las conexiones se caigan / fallen y he visto que hace que las bases de datos no vuelvan a funcionar correctamente (malo para la automatización). Sería bueno obtener una respuesta definitiva de mysql / Oracle. Deben tener una lista de correo.
Ryan Babchishin
7

He estafado y adaptado un script conceptualmente simple en Bash que encontré en otra publicación de Server Fault de Tobia . Debería llevarte aproximadamente el 90% del camino hasta allí.

mysql_locked=/var/run/mysql_locked

# flush & lock MySQL, touch mysql_locked, and wait until it is removed
mysql -hhost -uuser -ppassword -NB <<-EOF &
    flush tables with read lock;
    delimiter ;;
    system touch $mysql_locked
    system while test -e $mysql_locked; do sleep 1; done
    exit
EOF

# wait for the preceding command to touch mysql_locked
while ! test -e $mysql_locked; do sleep 1; done

# take a snapshot of the filesystem, while MySQL is being held locked
zfs snapshot zpool/$dataset@$(date +"%Y-%m-%d_%H:%M")

# unlock MySQL
rm -f $mysql_locked

Aquí, el mysqlcomando que usa se ejecuta en segundo plano y toca un archivo. Espera en segundo plano a que el archivo desaparezca antes de salir y, por lo tanto, desbloquear las tablas. Mientras tanto, el script principal espera hasta que el archivo exista, luego crea la instantánea y elimina el archivo.

El archivo señalado por $mysql_lockeddebe ser accesible para ambas máquinas, lo que debería poder hacer con bastante facilidad ya que ambos pueden acceder a un conjunto de datos común (aunque podrían usar rutas diferentes, y debe tener esto en cuenta).

Michael Hampton
fuente
No conozco las secuencias de comandos de MySQL, por lo que esta puede ser una idea tonta, pero ¿no podría simplemente hacerlo system zfs snapshot...dentro de la secuencia de comandos principal? ¿O el snap-shotting tiene que ejecutarse en un proceso separado?
TripeHound
@Tripehound ambas cosas deben suceder en paralelo de alguna manera
Ryan Babchishin
@RyanBabchishin Creo que tiene razón, en realidad. El SYSTEMcomando ejecuta las cosas localmente. Si ejecuto el cliente mysql en el cuadro de FreeBSD y ejecuto LOCK; SYSTEM zfs snapshot; UNLOCK, parece que funcionaría.
Andy Shulman
@ Andy, acabo de decir que deben suceder en paralelo. No importa cómo lo hagas.
Ryan Babchishin
2

Necesita FLUSH TABLES WITH READ LOCK para myisam porque no es diario.

Realmente no necesitas nada para innodb, IMO, porque es un diario. De todos modos, será consistente, solo retrocede el diario automáticamente si algo está sucediendo en el instante atómico de la instantánea.

Si desea que el nivel de aplicación sea coherente, su aplicación debe usar transacciones. Si su aplicación usa transacciones e innodb, cualquier instantánea será coherente, pregunte el camino al nivel de la aplicación automáticamente.

Jim Salter
fuente
2

Esta es mi solución para crear una instantánea de ZFS manteniendo el bloqueo:

mysql << EOF
    FLUSH TABLES WITH READ LOCK;
    system zfs snapshot data/db@snapname
    UNLOCK TABLES;
EOF
Petr Stastny
fuente