Sauvegarde d'une base de données MySQL via des instantanés ZFS

12

J'ai trouvé un certain nombre de sites qui parlent de faire exactement cela, mais je manque quelques détails importants. Les étapes générales sont

  • Courir FLUSH TABLES WITH READ LOCK
  • Prenez l'instantané ZFS
  • Courir UNLOCK TABLES

Diverses sources signalent qu'InnoDB, que j'utilise, ne respecte pas réellement a FLUSH. Le manuel d'utilisation de MySQL note qu'il existe une FLUSH TABLES...FOR EXPORTvariante à utiliser avec InnoDB, mais qui nécessite de spécifier chaque table individuellement, plutôt que de sauvegarder l'intégralité de la base de données. Je préfère éviter de spécifier chaque table individuellement car il y a de fortes chances que la liste des tables ne soit plus synchronisée avec les tables qui existent réellement.

L'autre problème que j'ai, c'est que j'avais prévu de faire quelque chose comme ça mysql -h"$HOST" -u"$USERNAME" -p"$PASSWORD" --execute="FLUSH TABLES WITH READ LOCK". Toutefois, cela supprime le verrou immédiatement après la fin de la session. Cela a du sens, mais est également assez ennuyeux car je dois maintenir le verrou de lecture lorsque je prends mon instantané.

Mon autre idée est de faire une sauvegarde à chaud en utilisant un outil comme Percona XtraBackup et de prendre des instantanés de la sauvegarde, mais je préférerais ne pas payer le coût d'écrire toutes mes données vers un deuxième emplacement juste pour les instantaner.

Andy Shulman
la source
Pourquoi avoir une liste statique de tableaux? Vous pouvez sûrement générer une liste dynamiquement lors de l'exécution.
EEAA
1
La base de données est-elle sur une machine virtuelle ou sur le métal nu? Le stockage est-il même sur la même machine?
Michael Hampton
EEAA, assez juste.
Andy Shulman
Michael, la base de données et la boîte ZFS sont des machines différentes, mais aucune n'est virtualisée.
Andy Shulman
@AndyShulman Je pense que vous devriez expliquer un peu mieux la mise en page. Cela n'a aucun sens.
ewwhite

Réponses:

4

Si vous utilisez uniquement InnoDB pour toutes les tables et que vous définissez innodb_flush_log_at_trx_commitsur:

  • 1 (le contenu du tampon de journalisation InnoDB est écrit dans le fichier journal à chaque validation de transaction et le fichier journal est vidé sur le disque) ou,
  • 2 (le contenu du tampon de journalisation InnoDB est écrit dans le fichier journal après chaque validation de transaction et le fichier journal est vidé sur le disque environ une fois par seconde),

alors vous n'avez pas besoin de FLUSH TABLES avant de faire un instantané, exécutez simplement l'instantané ZFS directement. InnoDB peut récupérer les données des journaux de validation des transactions sans perte de données.

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

Gea-Suan Lin
la source
Avec le dictionnaire de données introduit dans MySQL 8, même les opérations DDL (modification de schéma) sont désormais atomiques. Avant cela, les opérations DDL pendant un instantané de système de fichiers pouvaient donner des résultats partiellement validés (c'est-à-dire corrompus).
bernie
13

Vous avez besoin d'un verrou de base de données complet pour sauvegarder une (la plupart) base (s) de données de manière cohérente.

Le manuel https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html indique que TABLES DE RINÇAGE AVEC VERROUILLAGE EN LECTURE est correct pour les instantanés ZFS en particulier.

Création de sauvegardes à l'aide d'un instantané de système de fichiers

Si vous utilisez un système de fichiers Veritas, vous pouvez effectuer une sauvegarde comme celle-ci:

  1. À partir d'un programme client, exécutez FLUSH TABLES WITH READ LOCK.
  2. À partir d'un autre shell, exécutez le vxfssnapshot de montage .
  3. Depuis le premier client, exécutez UNLOCK TABLES.
  4. Copiez les fichiers à partir de l'instantané.
  5. Démontez l'instantané.

Des capacités d'instantané similaires peuvent être disponibles dans d'autres systèmes de fichiers, tels que LVM ou ZFS.

C'est un peu ridicule qu'ils aient omis le fait que vous ayez besoin FLUSH TABLES table_a, table_b, table_c FOR EXPORTd' InnoDB dans ces instructions. C'est aussi stupide de devoir spécifier chaque table comme ça. Mais comme le dit l'EEAA, vous pouvez générer une liste de tables lorsque vous commencez la sauvegarde assez facilement.

En ce qui concerne le maintien du verrou, vous devez garder la connexion db active pendant l'exécution de l'instantané

En général, j'utiliserais quelque chose comme Perl ou un autre langage de programmation qui peut se connecter, verrouiller la base de données et tout en maintenant la connexion db prendre l'instantané, puis déverrouiller et déconnecter. Ce n'est pas complexe. Je parierais qu'il existe déjà des outils qui le font déjà, mais en écrire un est facile.

Je dis facile, pas complexe, etc. à quelques reprises. Je suppose que vous avez une programmation de base ou de bonnes compétences en script.

Ryan Babchishin
la source
J'avais espéré garder un script aussi simple sur le plan conceptuel dans Bash, mais vous avez raison de changer de langue rend cela beaucoup plus facile. J'ai peut-être mal lu votre réponse, mais il semble que vous disiez que je dois exécuter les deux FLUSH TABLES WITH READ LOCKet ensuite FLUSH TABLES...FOR EXPORT, alors que ma lecture du manuel MySQL dit qu'une seule devrait être nécessaire.
Andy Shulman
Désolé, je n'ai pas été clair. Je vais juste par le manuel et il dit deux choses différentes. Je suppose que vous avez raison et que vous n'avez besoin que de la dernière. Mais toutes les tables doivent être verrouillées dans une seule commande.
Ryan Babchishin du
1
Étant donné que la documentation n'est pas très claire, la base de données entière doit être verrouillée et qu'une connexion à la base de données doit être maintenue pendant la capture de l'instantané, il semble plus facile de simplement fermer la base de données, de la sauvegarder et de redémarrer il.
Andrew Henle
2
@andrew soupire ... je comprends. Mais cela sera lent, provoquera la chute / l'échec des connexions et j'ai vu que les bases de données ne reviennent pas correctement (mauvais pour l'automatisation). Il serait bon d'obtenir une réponse définitive de mysql / Oracle. Ils doivent avoir une liste de diffusion.
Ryan Babchishin
7

Je l' ai arnaqué et adapté un script conceptuel simple Bash que j'ai trouvé dans un autre serveur de défaut après par Tobia . Cela devrait vous amener à environ 90% du chemin.

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

Ici, la mysqlcommande que vous utilisez est exécutée en arrière-plan et touche un fichier. Il attend en arrière-plan que le fichier disparaisse avant de quitter et donc de déverrouiller les tables. Pendant ce temps, le script principal attend que le fichier existe, puis crée l'instantané et supprime le fichier.

Le fichier indiqué par $mysql_lockeddoit être accessible aux deux machines, ce que vous devriez pouvoir faire assez facilement car ils peuvent tous deux accéder à un ensemble de données commun (bien qu'ils puissent utiliser des chemins différents, et vous devez en tenir compte).

Michael Hampton
la source
Je ne connais pas les scripts MySQL, donc cela peut être une idée idiote, mais ne pourriez-vous pas simplement faire system zfs snapshot...à l'intérieur du script principal? Ou le composant logiciel enfichable shotting ont à exécuter dans un processus distinct?
TripeHound
@Tripehound les deux choses doivent se produire en parallèle en quelque sorte
Ryan Babchishin
@RyanBabchishin Je pense qu'il a raison, en fait. La SYSTEMcommande exécute les choses localement. Si j'exécute le client mysql sur la boîte FreeBSD et l'exécute LOCK; SYSTEM zfs snapshot; UNLOCK, cela semble fonctionner.
Andy Shulman
@Andy, je viens de dire qu'ils doivent se produire en parallèle. Peu importe comment vous vous y prenez.
Ryan Babchishin
2

Vous avez besoin de TABLES DE RINÇAGE AVEC VERROUILLAGE DE LECTURE pour myisam car il ne s'agit pas de journalisation.

Vous n'avez vraiment pas besoin de quoi que ce soit pour innodb, OMI, parce que c'est de la journalisation. Il sera cohérent de toute façon, restaure automatiquement le journal si quelque chose se passe à l'instant atomique où vous prenez l'instantané.

Si vous souhaitez une cohérence au niveau de l'application, votre application doit utiliser des transactions. Si votre application utilise des transactions et innodb, tout instantané sera cohérent et demandera automatiquement le chemin jusqu'au niveau de l'application.

Jim Salter
la source
2

Voici ma solution pour créer un instantané ZFS tout en gardant le verrou:

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