Posts tagged with “backup”


Thu 28 Jul

Backups y restauraciones de tablas en InnoDB

Mucha gente cree erroneamente que gracias a la opción innodb-file-per-table te permite, como MyISAM, portar una tabla en binario de un servidor a otro de forma transparente o recuperar el backup de una tabla. El problema viene cuando realmente necesitan hacer uso de ese backup y no funciona como ellos esperaban.

Al contrario que con MyISAM, donde los ficheros de tablas MYD e MYI son independientes del resto y portables, todas las tablas de InnoDB dependen de un tablespace común donde se almacenan las definiciones de las tablas y además depende de los IDs de transacciones entre otras cosas. Por lo que, si restauras un .idb, no recuperarás los datos.

Todo esto se aplica a la versión original de MySQL, la desarrollada por Oracle. Pero Xtrabackup y Percona Server nos permite esquivar esta limitación y trabajar con los ficheros binarios como si se tratasen de tablas MyISAM, moviéndolas y restaurándolas de un servidor a otro.

Lo primero que sorprende es que el servidor de origen no tiene porque ser Percona Server, puede ser el MySQL del repositorio de tu distribución. Los únicos requisitos son:

  • El servidor origen y destino deben tener --innodb-file-per-table
  • Hacer el backup con xtrabackup
  • Recuperar el tablespace en un Percona Server

El proceso de realización del backup no cambia, pero si la posterior reparación (--prepare). El comando de reparación será el mismo, solo que añadimos la opción --export.

xtrabackup --prepare --export --innodb-file-per-table --target-dir=/mnt/backups/mysql-data

Esta opción generará un fichero extra .exp

/mnt/backups/mysql-data/db/table.exp
/mnt/backups/mysql-data/db/table.ibd

Ahora, ¿cómo importamos esa tabla en otro MySQL?

Tal y como hemos comentado antes, el destino debe ser un Percona Server. Únicamente tendremos que ejecutar los siguientes comandos:

ALTER TABLE db.table DISCARD TABLESPACE;

Copiamos las tablas exportadas al subdirectorio db/ del servidor destino.

ALTER TABLE db.table IMPORT TABLESPACE;

Y listo.

Tenéis información más actualizada en el propio manual de xtrabackup.

http://www.percona.com/docs/wiki/percona-xtrabackup:xtrabackup:export_and_import


Tue 1 Feb

Usando correctamente un esclavo como backup

Muchas de las instalaciones de replicación en MySQL no buscan ni balanceo de escrituras/lecturas ni alta disponibilidad, si no un simple backup en vivo. Montar una replicación es sencillo, no necesita hardware costoso y nos puede salvar de algunas situaciones complicadas. Por ejemplo, corrupción de tablas, errores en la controladora RAID o simplemente borrado de tablas directamente desde el sistema de ficheros. Si alguna de estas cosas pasa, tendremos el esclavo con un backup reciente de nuestros datos.

Pero la gente no tiene en cuenta que un backup usando esclavo no te salva de algunos errores humanos o de programación. Imaginemos que el empleado de recursos humanos se conecta a la base de datos de la empresa y quiere eliminar el salario de un trabajador recientemente despedido. Y ejecuta los siguientes comandos:

master [localhost] {msandbox} (employees) > show tables;
+---------------------+
| Tables_in_employees |
+---------------------+
| departments         |
| dept_emp            |
| dept_manager        |
| employees           |
| salaries            |
| titles              |
+---------------------+
7 rows in set (0.00 sec)

master [localhost] {msandbox} (employees) > delete from salaries;
Query OK, 2844047 rows affected (3 min 33.35 sec)

master [localhost] {msandbox} (employees) > select count(\*) from salaries;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

Está claro, nuestro compañero se ha equivocado. Ejecutar un delete olvidando un where es un error muy común aunque no lo parezca. Tu, como administrador, le tranquilizas diciéndole que no pasa nada, tienes un backup en el servidor esclavo. ¿Realmente lo tienes? La verdad es que no, el delete se ha propagado al esclavo. Tu compañero de RRHH se ha cargado la BBDD principal y el backup. Cuando se da un error de este tipo no hay tiempo para reaccionar, pierdes todo.

Como casi siempre, las famosas herramientas de administración maatkit vienen a salvarnos y hacer que nuestro esclavo backup sea aún más seguro. La herramienta que vamos a ver es mk-slave-delay. Como el nombre indica, permitirá añadir un delay a la replicación del esclavo del tiempo que nosotros le digamos.

Options:
  --askpass          Prompt for password for connections
  --[no]continue -c  Continue replication normally on exit (default)
  --daemonize        Fork to background and detach (POSIX only)
  --delay        -d  Slave delay (default 1h).  Optional suffix s=seconds,
                     m=minutes, h=hours, d=days; if no suffix, s is used.
  --help             Show this help message
  --interval     -i  Sleep interval (default 1m).  Optional suffix s=seconds,
                     m=minutes, h=hours, d=days; if no suffix, s is used.
  --quiet        -q  Suppress normal output
  --setvars          Set these MySQL variables (default wait_timeout=10000)
  --time         -t  Time to run before exiting.  Optional suffix s=seconds,
                     m=minutes, h=hours, d=days; if no suffix, s is used.
  --usemaster    -u  Get binlog positions from master, not slave
  --version          Output version information and exit

Así que ejecutamos lo siguiente:

mk-slave-delay --daemonize -d 1h h=localhost,u=msandbox,p=msandbox,S=/tmp/mysql_sandbox13214.sock

Con esto, mk-slave-delay se pasara a background como demonio y se conectará a localhost creando un delay en la replicación de 1 hora. Esto es, desde que tu aplicas un cambio en el master hasta que este llega al esclavo pasará una hora. El funcionamiento interno es muy simple, consiste en parar y arrancar el SQL thread

Gracias a esto, desde el momento en el que el compañero de RRHH comete el error tienes una hora de tiempo de reloj para conectarte al esclavo, parar la replicación y sacar un dump. Y claro está, el valor de tiempo es modificable a gusto del consumidor. De esta forma, además de estar protegido de los típicos fallos que se puedan dar en el maestro, también estarás protegido de los fallos humanos o de programación :) Por lo tanto, si tienes un esclavo como backup, es muy recomendable meterle un delay. Luego, todas las sentencias que has perdido por ese tiempo de retraso puedes recuperarla de los binlogs pero evitando la última sentencia que eliminó todos tus datos.

slave1 [localhost] {msandbox} (employees) > select count(\*) from salaries;
+----------+
| count(*) |
+----------+
|  2844047 |
+----------+
1 row in set (0.70 sec)


Sat 20 Nov

Backup online y consistente en MySQL Cluster

En MySQL Cluster existen diferentes formas de hacer backup y debido a su arquitectura distribuida hay unas más recomendables que otras. Aquí vamos a ver la nativa, usando el cliente nbd_mgm. Desde esta herramienta de control podremos lanzar ordenes de backup que ejecutará cada nodo de almacenamiento, sacando un snapshot consistente de los datos y sin necesidad de parar el sistema.

Un backup en MySQL Cluster consiste en tres ficheros:

  • Metadatos

BACKUP-backup_id.node_id.ctl

Es un fichero donde se guardan las definiciones de las tablas.

  • Datos de las tablas

BACKUP-backup_id-0.node_id.data

Cada nodo guardará en este fichero los fragmentos de las tablas que gestiona.

  • Log de transacciones

BACKUP-backup_id.node_id.log

Es el log de las transacciones con commit de las que se harán backup.

Siendo backup_id el identificador del backup y node_id el identificador del nodo. Cada nodo guardará los ficheros en su disco local, pero es recomendable que todos escriban al mismo destino, posiblemente un NAS, ya que a la hora de recuperar tendremos que tener accesibles todos los ficheros de cada nodo desde una única ubicación.

Para lanzar el backup nos conectamos con la utilidad ndb_mgm al management node y ejecutamos:

ndb_mgm> START BACKUP

Por defecto la herramienta se quedará parada (no podremos ejecutar más comandos) hasta que el backup se complete (WAIT COMPLETED). Pero podremos cambiar este comportamiento añadiendo el parámetro NOWAIT o WAIT STARTED.

Para parar un backup:

ndb_mgm> ABORT BACKUP id

Para definir donde queremos que vayan nuestros backups debemos hacer global para todos los nodos el parámetro BackupDataDir.

Como hemos visto, hacer un backup en caliente es sencillo y no tienen ningún tipo de downtime. Esto no es así para el proceso de restauración, que no debería hacerse online. Como indica la documentación de MySQL, el engine NDB no soporta repeatable reads. Por lo tanto durante el proceso de restauración las transacciones en ejecución reciben lecturas no repetidas (nonrepeatable) y por lo tanto tendremos datos incosistentes.

Se recomienda por ello hacer la restauración con el Cluster parado para evitar esta serie de problemas. Para ello lanzamos el Cluster en Single Mode de forma que un único API node (ndb_restore) tenga acceso a los datos.

Para restaurar un backup haremos uso de la utilidad ndb_restore:

ndb_restore [-c connectstring] -n node_id [-m] -b backup_id -r 
--backup_path=/path/to/backup/files

Donde:

  • connectstring: dirección ip y puerto del management node.
  • node_id: número de nodo a restaurar
  • backup_id: id de backup a restaurar
  • -m: si deseamos recrear las tablas a partir de los metadatos
  • backup_path: ruta donde se encuentran los archivos con nuestros backups

Habrá que ejecutarlo una vez por cada nodo. Una vez restaurado podemos salir del Single Mode y permitir así de nuevo el acceso a los lusers.


Thu 25 Feb

Nuevas trasparencias: administración avanzada de MySQL

Aquí os pongo unas nuevas transparencias de un curso que he dado recientemente. Abarca gran cantidad de temas relacionados con la administración de nuestra base de datos favorita :)

  • Instalación
  • Engines
  • Optimización de consultas
  • Optimización de tablas
  • Optimización del servicio
  • Usuarios y permisos
  • Replicación
  • Alta disponibilidad
  • Backup
  • etc. :)

Espero que os guste y os sea de utilidad. Cualquier sugerencia o crítica es bienvenida. Si hay algún fallo comentádmelo para solucionarlo lo antes posible.

¡Gracias a todos!