récupérer une seule base de données mysql sur un système répliqué maître-esclave occupé

10

Vous recherchez une stratégie ou un outil pour gérer la récupération d'une base de données unique à un point dans le temps dans un système répliqué occupé.

J'ai 12 bases de données fonctionnant sur 2 serveurs MySQL 5.0.77 en configuration répliquée maître-esclave. Un vidage complet est effectué quotidiennement de l'esclave en lecture seule, et des vidages SQL incrémentiels sont disponibles, avec ces sauvegardes hors site et l'état de réplication est surveillé.

Edit: les tableaux sont un mélange d'InnoDB et de myISAM, donc les solutions spécifiques au moteur ne sont pas disponibles.

Donc, en cas d'échec complet du serveur maître, je peux interrompre la réplication et promouvoir le serveur esclave, j'ai également la possibilité de reconstruire un nouveau serveur et de configurer à partir de la sauvegarde FULL hors-jeu, puis d'appliquer les écarts pris toutes les heures à l'esclave.

Cependant, je me demande comment faire face à une défaillance partielle ou à la défaillance d'une seule base de données. Je peux penser à 2 scénarios qui sont très probables;

  1. la base de données 7 (par exemple) est corrompue, continue de répondre à certaines demandes jusqu'à ce que quelqu'un remarque qu'elle est cassée ou alerte les fichiers journaux ...
  2. Certaines requêtes, telles que drop database, drop table, "update where ..." type query borks a single database, or some subet there.

Pour le moment, j'ai un tas de vidages complets en tant que fichiers FULL- $ DATE-all-databases.sql.gz, et des différences qui peuvent être appliquées aux vidages complets en tant que DIFF- $ DATE-all-databases.sql.gz

Pour restaurer la base de données 7 à un certain point dans le temps, il faudrait un grep à travers les fichiers FULL et DIFF, et une application manuelle de ce sql.

Comment dois-je procéder pour pouvoir récupérer sur l'un des précédents vidages DIFF vers la base de données master?

DOIS-JE sauvegarder sur des fichiers de base de données individuels, c.-à-d.

mysqldump --databases "database1" | gzip > database1.sql.gz
mysqldump --databases "database2" | gzip > database2.sql.gz
mysqldump --databases "database3" | gzip > database3.sql.gz

plutôt que..

mysqldump --master-data --lock--all-databases --all-databases | gzip > all-databases.sql.gz

Si je choisis des fichiers mysqldump séparés, qu'arrive-t-il au journal binaire des données de base et dois-je même définir --master-data pour les vidages de récupération du serveur maître?

Tom H
la source

Réponses:

7

Si toutes vos bases de données utilisent InnoDB uniquement, j'ai de bonnes nouvelles.

Vous devriez être en train de vider toute la base de données en parallèle depuis un esclave.

En fait, vous pouvez forcer toutes les bases de données dans le même point dans le temps.

La première chose à retenir à propos d'un esclave est qu'il n'est pas nécessaire d'activer la journalisation binaire s'il n'est pas un maître pour d'autres esclaves.

Vous ne pouvez pas utiliser l' --master-dataoption pour les vidages parallèles car chaque vidage aura une position différente écrite à la ligne 22 de chaque fichier de vidage. Il est préférable d'enregistrer le dernier fichier journal du maître et de positionner l'esclave exécuté à l'aide de SHOW SLAVE STATUS\G. De cette façon, toutes les bases de données ont la même position ponctuelle.

Vous pouvez collecter toutes les bases de données et scripter le vidage parallèle de toutes les bases de données.

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
done 
wait 

mysql -h... -u... -p... -e"START SLAVE;"

S'il y a simplement trop de bases de données, videz-les 10 ou 20 à la fois comme suit:

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

Si vous devez récupérer une seule table, vous pouvez mettre en parallèle les tables de vidage 20 à la fois dans l'ordre de taille.

Essaye ça:

TBLIST=/tmp/ListOfTablesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql','performance_schema') ORDER BY data_length" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DBTB in `cat ${TBLIST}` 
do
    DB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $1}'`
    TB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $2}'`
    DUMPFILE=$DB-{DB}-TBL-${TB}.sql.gz
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} ${TB} | gzip >  ${DUMPFILE} & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

Maintenant que vous disposez de scripts pour vider les bases de données ou les tables individuelles, vous pouvez charger ces données à votre discrétion. Si vous avez besoin d'exécuter SQL à partir des journaux binaires sur le maître, vous pouvez utiliser mysqlbinloget lui donner la position de datetime et sortir le SQL vers d'autres fichiers texte. Il vous suffit de faire preuve de diligence raisonnable pour trouver la quantité de données dont vous avez besoin à partir des horodatages des journaux binaires. N'oubliez pas que l'horodatage de chaque journal binaire dans le système d'exploitation représente la dernière fois qu'il a été écrit.

RolandoMySQLDBA
la source
réponses brillantes merci. Je pense qu'avoir un esclave en lecture seule sur xfs me donne beaucoup d'options, et vos scripts ont vraiment aidé.
Tom H
dans le scénario où je dois récupérer une table massive sur le maître à partir d'une sauvegarde de l'esclave. Je dois juste reconstruire la table sur le maître, et faire répliquer toutes les modifications sur l'esclave, même si c'est 20 Go de données? Le processus serait-il 1) désactiver les clés, 2) déposer la table sur le maître et l'esclave 3) restaurer la table le maître 4) activer les clés --- et demander au maître de répliquer les 20 Go vers l'esclave?
Tom H
Si ces bases de données ne sont PAS innodb, puis-je quand même les vider en parallèle?
Tom H
Oui, si vous 1) planifiez un temps d'arrêt, 2) exécutez service mysql restart --skip-networking, 3) effectuez le vidage parallèle, 4) exécutez service mysql restart. Rechargez ensuite les tables dont vous avez besoin.
RolandoMySQLDBA
sans doute si le but du redémarrage était d'empêcher les connexions réseau d'écrire dans la base de données, alors je pourrais obtenir le même effet en utilisant iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROPsur eth0 et lo
Tom H