web-dev-qa-db-fra.com

Le moyen le plus sûr d'effectuer mysqldump sur un système en direct avec des lectures et des écritures actives?

Je ne sais pas si cela est vrai, mais je me souviens avoir lu si vous exécutez la commande suivante sous linux

mysqldump -u username -p database_name > backup_db.sql

pendant la lecture et l'écriture dans une base de données, le vidage peut contenir des erreurs.

Existe-t-il des options particulières dans la commande mysqldump pour vous assurer que cela se fait en toute sécurité sur un système en direct? Je suis d'accord avec la lecture/écriture désactivée pour nos utilisateurs pendant quelques secondes (la base de données <50 Mo)

85
user784637

Toutes les données sont InnoDB

Voici ce qui vous donnera un instantané exact des données:

mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

--single-transaction produit un point de contrôle qui permet au vidage de capturer toutes les données avant le point de contrôle lors de la réception des modifications entrantes. Ces modifications entrantes ne font pas partie du vidage. Cela garantit le même point dans le temps pour toutes les tables.

--routines vide toutes les procédures et fonctions stockées

--triggers vide tous les déclencheurs pour chaque table qui les a

Toutes les données sont MyISAM ou un mélange d'InnoDB/MyISAM

Vous devrez imposer un verrou de lecture global, effectuer le mysqldump et libérer le verrou global

mysql -uuser -ppass -Ae"FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400)" &
sleep 5
mysql -uuser -ppass -ANe"SHOW PROCESSLIST" | grep "SELECT SLEEP(86400)" > /tmp/proclist.txt
SLEEP_ID=`cat /tmp/proclist.txt | awk '{print $1}'`
echo "KILL ${SLEEP_ID};" > /tmp/kill_sleep.sql
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql
mysql -uuser -ppass -A < /tmp/kill_sleep.sql

Essaie !!!

MISE À JOUR 2012-06-22 08:12 EDT

Puisque vous avez <50 Mo de données totales, j'ai une autre option. Au lieu de lancer une commande SLEEP en arrière-plan pour maintenir le verrou de lecture global pendant 86400 secondes (que 24 heures) juste pour obtenir l'ID de processus et tuer à l'extérieur, essayons de définir un délai d'expiration de 5 secondes dans mysql plutôt que dans le système d'exploitation:

SLEEP_TIMEOUT=5
SQLSTMT="FLUSH TABLES WITH READ LOCK; SELECT SLEEP(${SLEEP_TIMEOUT})"
mysql -uuser -ppass -Ae"${SQLSTMT}" &
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

Il s'agit d'une approche plus propre et plus simple pour les très petites bases de données.

90
RolandoMySQLDBA
  • Pour les tables InnoDB, vous devez utiliser le --single-transaction option, comme mentionné dans une autre réponse.
  • Pour MyISAM, il y a --lock-tables.

Voir le documentation officielle ici

4
pesco

La suggestion de la documentation officielle mysql est que vous devriez avoir une base de données maître "M1" et une base de données esclave "S1" qui est décrite dans "Scénario 2: Sauvegarde avec un esclave en lecture seule" Sauvegarde d'un maître ou Esclave en le rendant en lecture seule

Vous devez définir la base de données esclave en lecture seule et effectuer e

1

Voici comment je l'ai fait. Il devrait fonctionner dans tous les cas car il utilise FLUSH TABLES WITH READ LOCK.

#!/bin/bash

DB=example
DUMP_FILE=export.sql

# Lock the database and sleep in background task
mysql -uroot -proot $DB -e "FLUSH TABLES WITH READ LOCK; DO SLEEP(3600);" &
sleep 3

# Export the database while it is locked
mysqldump -uroot -proot --opt $DB > $DUMP_FILE

# When finished, kill the previous background task to unlock
kill $! 2>/dev/null
wait $! 2>/dev/null

echo "Finished export, and unlocked !"

La commande Shell sleep sert uniquement à s'assurer que la tâche en arrière-plan exécutant la commande de verrouillage mysql est exécutée avant le démarrage de mysqldump. Vous pouvez le réduire à 1 seconde et cela devrait toujours être bien. Augmentez-le à 30 secondes et essayez d'insérer des valeurs dans n'importe quelle table d'un autre client pendant ces 30 secondes, vous verrez qu'il est verrouillé.

Il y a 2 avantages à utiliser ce verrouillage manuel en arrière-plan, au lieu d'utiliser les options mysqldump--single-transaction et --lock-tables:

  1. Cela verrouille tout, si vous avez mélangé des tables MyISAM/InnoDB.
  2. Vous pouvez exécuter d'autres commandes en plus de mysqldump pendant la même période de verrouillage. C'est utile, par exemple, lors de la configuration de la réplication sur un nœud maître, car vous devez obtenir la position du journal binaire avec SHOW MASTER STATUS; à l'état exact du vidage que vous avez créé (avant de déverrouiller la base de données), pour pouvoir créer un esclave de réplication.
1
Nicomak

Si vous souhaitez le faire pour MyISAM ou des tables mixtes sans aucun temps d'arrêt du verrouillage des tables, vous pouvez configurer une base de données esclave et prendre vos instantanés à partir de là. La configuration de la base de données esclave, malheureusement, entraîne un certain temps d'arrêt pour exporter la base de données en direct, mais une fois qu'elle est en cours d'exécution, vous devriez pouvoir verrouiller ses tables et exporter en utilisant les méthodes décrites par d'autres. Lorsque cela se produit, il sera en retard sur le maître, mais n'empêchera pas le maître de mettre à jour ses tables et rattrapera son retard dès que la sauvegarde sera terminée.

1
Talik Eichinger

si vous avez une très grande table MYISAM et que vous devez vider la table sans verrou et éviter une charge de serveur élevée, vous pouvez utiliser le script suivant.

#!/bin/sh

my_user="user"
my_password="password"
my_db="vpn"
my_table="traffic"
my_step=100000

read -p "Dumping table ${my_db}.${my_table} to ${my_table}.sql?" yn
case $yn in
    [Yy]* ) break;;
    * ) echo "User cancel."; exit;;
esac

my_count=$(mysql $my_db -u $my_user -p$my_password -se "SELECT count(*) FROM $my_table")
my_count=$(($my_count + 0))

if [ ! $my_count ]
then
    echo "No records found"
    exit
fi

echo "Records in table ${my_db}.${my_table}: ${my_count}"

echo "" > $my_table.sql

max_progress=60

for (( limit=0; limit<=$my_count; limit+=$my_step )); do
    progress=$((max_progress * ( limit + my_step) / my_count))

    echo -ne "Dumping ["
    for ((i=0; i<$progress; i ++)); do
        echo -ne "#"
    done
    for ((; i<$max_progress; i ++)); do
        echo -ne "."
    done

    mysqldump -u $my_user -p$my_password --complete-insert --no-create-info --opt --where="1 limit $limit , $my_step" $my_db $my_table >> $my_table.sql
    echo "" >> $my_table.sql

    echo -ne "] $((100 * ( limit + my_step ) / my_count)) %"
    echo -ne "\r"

    sleep 1

done

echo -ne "\n"
0
vadim_hr