ripristinare un singolo database mysql su un sistema replicato master-slave occupato


10

Alla ricerca di una strategia o di uno strumento per gestire il ripristino di un singolo database in un punto temporale in un sistema replicato occupato.

Ho 12 database in esecuzione su 2 server MySQL 5.0.77 in configurazione replicata master-slave. Viene eseguito giornalmente un dump completo dello slave di sola lettura e sono disponibili dump SQL incrementali, con questi backup fuori sede e lo stato della replica viene monitorato.

Modifica: le tabelle sono una miscela di InnoDB e myISAM, quindi non sono disponibili soluzioni specifiche per il motore.

Quindi, dato un completo fallimento del server principale, posso interrompere la replica e promuovere il server slave, ho anche la possibilità di ricostruire un nuovo server e configurare dal backup COMPLETO offside, e quindi applicare i differenziali presi ogni ora dallo slave.

Tuttavia, mi preoccupo di come gestire l'errore parziale o l'errore di un singolo database. Posso pensare a 2 scenari che sono abbastanza probabili;

  1. il database 7 (ad esempio) viene danneggiato, continua a servire alcune richieste fino a quando qualcuno non si accorge che è rotto o avvisa dai file di registro ...
  2. Alcune query come drop database, drop table, query "aggiorna dove ..." inseriscono un singolo database o alcuni sottoinsiemi.

Al momento ho un sacco di dump COMPLETI come file FULL- $ DATE-all-d Database.sql.gz e differenziali che possono essere applicati ai dump COMPLETI come DIFF- $ DATE-all-d Database.sql.gz

Ripristinare il database 7 in un determinato momento richiederebbe un grep attraverso i file FULL e DIFF e l'applicazione manuale di quel sql.

Come devo procedere per rendere possibile il ripristino in uno dei precedenti dump DIFF nel database principale?

Devo eseguire il backup su singoli file di database, ad es

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

piuttosto che..

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

Se scelgo file mysqldump separati, cosa succede al registro binario dei dati master e dovrei anche impostare --master-data per i dump di ripristino del server master?

Risposte:


7

Se tutto il tuo database utilizza solo InnoDB, ho delle buone notizie.

Dovresti scaricare tutto il database in parallelo da uno slave.

In effetti, è possibile forzare tutti i database nello stesso punto temporale.

La prima cosa da ricordare su uno Slave è che non è necessario avere la registrazione binaria abilitata se non è un Master per altri Slave.

Non è possibile utilizzare l' --master-dataopzione per i dump paralleli perché ogni dump avrà una posizione diversa scritta alla riga 22 di ciascun file dump. È meglio registrare l'ultimo file di registro del Master e posizionare lo Slave eseguito usando SHOW SLAVE STATUS\G. In questo modo, tutti i database hanno la stessa posizione temporizzata.

È possibile raccogliere tutti i database e eseguire lo script del dump parallelo di tutto il database.

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;"

Se ci sono semplicemente troppi database, scaricarli 10 o 20 alla volta come segue:

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;"

Se è necessario ripristinare una singola tabella, è possibile parallelizzare le tabelle di dump 20 alla volta in ordine di dimensione.

Prova questo:

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;"

Ora che hai script per scaricare database o singole tabelle, puoi caricare quei dati a tua discrezione. Se è necessario eseguire SQL dai registri binari sul master, è possibile utilizzarlo mysqlbinloge assegnargli la posizione di datetime e generare l'SQL su altri file di testo. Devi solo eseguire la dovuta diligenza per trovare la quantità di dati di cui hai bisogno da qualsiasi timestamp dei registri bnary. Basta ricordare che il timestamp di ogni registro binario nel sistema operativo rappresenta l'ultima volta che è stato scritto.


risposte brillanti grazie. Penso che avere uno slave di sola lettura su xfs mi offra un sacco di opzioni e i tuoi script mi ​​hanno davvero aiutato.
Tom H,

nello scenario in cui ho bisogno di recuperare una tabella enorme per il master da un backup dallo slave. Devo solo ricostruire la tabella sul master e fare in modo che tutte le modifiche vengano replicate nello slave, anche se si tratta di 20 GB di dati? Il processo sarebbe 1) disabilitare le chiavi, 2) rilasciare la tabella su master e slave 3) ripristinare la tabella su master 4) abilitare le chiavi --- e far sì che il master replicasse tutti i 20 GB fino allo slave?
Tom H,

Se questi database NON sono innodb, posso comunque scaricarli in parallelo?
Tom H,

Sì, se 1) pianifica i tempi di inattività, 2) esegui service mysql restart --skip-networking, 3) esegui il dump parallelo, 4) esegui service mysql restart. Quindi ricaricare le tabelle necessarie.
RolandoMySQLDBA

presumibilmente se lo scopo del riavvio fosse impedire alle connessioni di rete di scrivere nel database, allora avrei potuto ottenere lo stesso effetto usando iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROPsu eth0 e lo
Tom H,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.