Configuration des sauvegardes MySQL incrémentielles avec Percona XtraBackup

Construisez et restaurez des sauvegardes MySQL incrémentielles avec Percona XtraBackup, en utilisant des sauvegardes complètes, le chaînage LSN, les étapes de préparation et la copie de retour.

Configuration des sauvegardes MySQL incrémentielles avec Percona XtraBackup

Percona XtraBackup (PXB) peut effectuer des sauvegardes à chaud de serveurs compatibles MySQL avec des données InnoDB. Les sauvegardes complètes sont simples, mais les grandes bases de données nécessitent souvent des sauvegardes MySQL incrémentielles pour éviter de copier les mêmes pages chaque nuit.

Ce guide couvre les commandes pour une sauvegarde complète de base, les sauvegardes incrémentielles chaînées et la séquence de restauration qui applique chaque incrémentielle dans l'ordre.

Comprendre le mécanisme incrémentiel de Percona XtraBackup

PXB repose sur le fonctionnement interne du moteur de stockage InnoDB, en particulier le suivi des modifications à l'aide du numéro de séquence de journal (LSN). Chaque page InnoDB est étiquetée avec un LSN. Lorsque PXB effectue une sauvegarde incrémentielle, il enregistre uniquement les pages dont le LSN est supérieur au LSN enregistré au moment de la sauvegarde précédente.

Crucialement, les sauvegardes incrémentielles nécessitent une sauvegarde complète de base pour établir le point de départ. Toutes les sauvegardes incrémentielles suivantes sont chaînées, en référence à la sauvegarde immédiatement précédente (qui peut être la sauvegarde de base ou une autre incrémentielle).

Fichiers et concepts clés

  • LSN (Log Sequence Number) : Le marqueur utilisé pour déterminer où les changements commencent et se terminent.
  • xtrabackup_checkpoints : Un fichier créé lors de chaque sauvegarde contenant to_lsn (le LSN atteint à la fin de la sauvegarde) et, pour les sauvegardes incrémentielles, from_lsn (le LSN de départ).
  • --incremental-basedir : Le drapeau essentiel utilisé lors des exécutions incrémentielles, pointant PXB vers le répertoire de la sauvegarde précédente (qui détermine le LSN de départ).

Étape 1 : Effectuer la sauvegarde complète de base

Avant de prendre des instantanés incrémentiels, une sauvegarde complète et cohérente doit être créée. Cela établit la base de toute la chaîne de sauvegarde.

Commencez par définir un répertoire clair pour la sauvegarde complète :

# Définir le répertoire de base pour la sauvegarde complète
BASE_DIR="/data/backups/2023-10-01_FULL"

# Créer le répertoire
mkdir -p $BASE_DIR

# Exécuter la sauvegarde complète
xtrabackup --backup \
  --target-dir=$BASE_DIR \
  --user=root --password=secret_password \
  --datadir=/var/lib/mysql

# Vérifier le LSN de la sauvegarde complète
cat $BASE_DIR/xtrabackup_checkpoints | grep 'to_lsn'

Remarque : Le target-dir doit être vide ou inexistant au début du processus de sauvegarde. Les privilèges requis varient selon les versions de MySQL et XtraBackup, créez donc un utilisateur de sauvegarde dédié en utilisant les directives de privilèges actuelles de Percona plutôt que de réutiliser root.

Étape 2 : Effectuer la première sauvegarde incrémentielle

Pour effectuer la première sauvegarde incrémentielle, nous devons référencer le répertoire de la sauvegarde complète de base en utilisant le drapeau --incremental-basedir. PXB lira le to_lsn de la sauvegarde de base et ne copiera que les pages qui ont changé depuis ce point.

# Définir le répertoire pour la première sauvegarde incrémentielle
INCREMENTAL_1_DIR="/data/backups/2023-10-02_INC1"

# Exécuter la sauvegarde incrémentielle, en référence à la sauvegarde complète de base
xtrabackup --backup \
  --target-dir=$INCREMENTAL_1_DIR \
  --incremental-basedir=/data/backups/2023-10-01_FULL \
  --user=root --password=secret_password

Étape 3 : Chaîner les sauvegardes incrémentielles suivantes

Pour toute sauvegarde incrémentielle suivante (INC2, INC3, etc.), le --incremental-basedir doit pointer vers le répertoire de la sauvegarde incrémentielle immédiatement précédente.

Si nous voulons créer INC2 basée sur les changements depuis INC1 :

# Définir le répertoire pour la deuxième sauvegarde incrémentielle
INCREMENTAL_2_DIR="/data/backups/2023-10-03_INC2"

# Exécuter la sauvegarde incrémentielle, en référence à la sauvegarde incrémentielle précédente (INC1)
xtrabackup --backup \
  --target-dir=$INCREMENTAL_2_DIR \
  --incremental-basedir=/data/backups/2023-10-02_INC1 \
  --user=root --password=secret_password

Ce chaînage continue tant que vous maintenez la séquence. Si un maillon de la chaîne est cassé (c'est-à-dire qu'un répertoire est manquant), le processus de restauration échouera.

Restauration : Application des modifications incrémentielles

La restauration d'un ensemble de sauvegardes incrémentielles est un processus en plusieurs étapes qui consiste à appliquer les modifications séquentiellement à la sauvegarde de base. Contrairement à une sauvegarde complète, les sauvegardes incrémentielles ne peuvent pas être copiées directement dans le répertoire de données.

Phase de restauration 1 : Préparation de la sauvegarde de base

Tout d'abord, la sauvegarde de base doit être préparée. Cela se fait généralement dans une zone de transit temporaire pour garantir la sécurité des données.

Lors de la préparation de la sauvegarde de base, PXB effectue deux actions essentielles :

  1. Applique les transactions validées (le journal de redo).
  2. Annule les transactions non validées.

Nous utilisons le drapeau --prepare, mais de manière cruciale, nous ajoutons le drapeau --apply-log-only. Cela empêche PXB d'annuler les transactions non validées, ce qui est nécessaire car les journaux incrémentiels suivants ont besoin de ces fragments de transaction pour terminer la restauration.

# Définir le répertoire de transit
RESTORE_TARGET="/data/restore_staging"

# Copier les fichiers de la sauvegarde complète de base dans la zone de transit
rsync -avr /data/backups/2023-10-01_FULL/ $RESTORE_TARGET

# Préparer la sauvegarde de base, en la gardant prête pour les incréments
xtrabackup --prepare --target-dir=$RESTORE_TARGET --apply-log-only

# Rechercher la confirmation : 'completed OK!'

Phase de restauration 2 : Application séquentielle des sauvegardes incrémentielles

Ensuite, appliquez chaque sauvegarde incrémentielle dans l'ordre chronologique exact où elles ont été prises. Chaque commande doit référencer le répertoire de transit (la sauvegarde de base en cours de modification) et utiliser le drapeau --incremental-dir pointant vers l'instantané incrémentiel spécifique.

# Appliquer l'incrément 1
xtrabackup --prepare --target-dir=$RESTORE_TARGET \
  --incremental-dir=/data/backups/2023-10-02_INC1 \
  --apply-log-only

# Appliquer l'incrément 2
xtrabackup --prepare --target-dir=$RESTORE_TARGET \
  --incremental-dir=/data/backups/2023-10-03_INC2 \
  --apply-log-only

# ... continuer pour tous les incréments nécessaires ...

Phase de restauration 3 : Finalisation de la préparation

Une fois le dernier instantané incrémentiel souhaité appliqué, exécutez l'étape de préparation finale sans le drapeau --apply-log-only. Cela permet à PXB d'effectuer le nettoyage final, en annulant toutes les transactions qui étaient encore non validées dans toute la séquence de sauvegarde, résultant en un état cohérent.

# Finaliser la préparation (sans --apply-log-only)
xtrabackup --prepare --target-dir=$RESTORE_TARGET

# IMPORTANT : Rechercher la confirmation finale indiquant 'xtrabackup: Recovery completed OK!'

Phase de restauration 4 : Copie des données vers MySQL

Après une préparation réussie, les données dans le répertoire de transit ($RESTORE_TARGET) sont cohérentes et prêtes à être utilisées par le serveur MySQL.

  1. Arrêtez le service MySQL.
  2. Assurez-vous que le répertoire de données MySQL est vide ou sauvegardé (optionnel : utilisez l'option --move-back si autorisé, mais --copy-back est plus sûr pour la récupération).
  3. Utilisez xtrabackup --copy-back pour déplacer les fichiers.
  4. Corrigez les permissions.
  5. Redémarrez MySQL.
# Arrêter le service MySQL
sudo systemctl stop mysql

# Copier les fichiers préparés vers le répertoire de données MySQL
xtrabackup --copy-back --target-dir=$RESTORE_TARGET

# Assurer la propriété appropriée des fichiers
sudo chown -R mysql:mysql /var/lib/mysql

# Démarrer MySQL
sudo systemctl start mysql

Meilleures pratiques pour la gestion des sauvegardes incrémentielles

Automatisation et scripts

Les stratégies de sauvegarde incrémentielle sont plus efficaces lorsqu'elles sont entièrement automatisées. Les scripts doivent gérer automatiquement le chaînage LSN, en identifiant dynamiquement le répertoire de sauvegarde le plus récent à utiliser pour le drapeau --incremental-basedir.

Politique de rétention

Les chaînes incrémentielles peuvent devenir très longues, rendant la restauration lente et fragile. Périodiquement, renouvelez la chaîne en effectuant une nouvelle sauvegarde complète. Certaines équipes conservent également des sauvegardes complètes hebdomadaires et mensuelles selon un modèle de rétention Grand-père-Père-Fils.

Compression et limitation

Pour les serveurs très occupés, envisagez d'utiliser l'option --throttle pendant la phase de sauvegarde pour limiter les opérations d'E/S. Utilisez --compress pour réduire la taille de la sauvegarde, ce qui est très bénéfique pour les ensembles de données plus petits générés par les sauvegardes incrémentielles.

# Exemple avec compression et limitation
xtrabackup --backup \
  --target-dir=$INCREMENTAL_3_DIR \
  --incremental-basedir=$INCREMENTAL_2_DIR \
  --compress \
  --throttle=100

Vérification et surveillance

Testez toujours régulièrement vos procédures de restauration. Une sauvegarde qui ne peut pas être restaurée est inutile. Surveillez l'espace disque consommé par votre chaîne incrémentielle, surtout avant d'initier une nouvelle sauvegarde complète de base.

Conclusion

XtraBackup incrémentiel fonctionne uniquement lorsque la chaîne est intacte : sauvegarde complète, première incrémentielle basée sur la sauvegarde complète, puis chaque incrémentielle suivante basée sur la sauvegarde précédente. Lors de la restauration, préparez la base avec --apply-log-only, appliquez chaque incrémentielle dans l'ordre, exécutez une dernière préparation sans --apply-log-only, et ensuite seulement copiez les données préparées vers MySQL.