восстановить одну базу данных mysql в занятой реплицированной системе «главный-подчиненный»

10

Ищите стратегию или инструмент для восстановления одной базы данных на определенный момент времени в занятой реплицируемой системе.

У меня 12 баз данных, работающих на 2 серверах MySQL 5.0.77 в реплицированной конфигурации master-slave. Ежедневно выполняется полный дамп ведомого устройства, доступного только для чтения, и доступны инкрементные дампы SQL, при этом эти резервные копии находятся за пределами сайта и отслеживается состояние репликации.

Изменить: таблицы представляют собой смесь InnoDB и myISAM, поэтому конкретные решения для двигателей не доступны.

Таким образом, при полном отказе главного сервера, я могу прервать репликацию и продвинуть подчиненный сервер, у меня также есть возможность перестроить новый сервер и настроить его из резервной полной резервной копии, а затем применить дифференциалы, почасовые из ведомого.

Однако меня беспокоит, как бороться с частичным сбоем или сбоем одной базы данных. Я могу вспомнить 2 сценария, которые вполне вероятны;

  1. база данных 7 (например) становится поврежденной, продолжает обслуживать некоторые запросы до тех пор, пока кто-то не заметит, что она повреждена, или не выдаст оповещения из файлов журнала ...
  2. Некоторые запросы, такие как удаление базы данных, удаление таблицы, запрос типа "обновить где ...", содержат только одну базу данных или некоторое подмножество в ней.

На данный момент у меня есть куча FULL-дампов в виде файлов FULL- $ DATE-all-database.sql.gz и различий, которые можно применять к FULL-дампам в виде DIFF- $ DATE-all-database.sql.gz.

Чтобы восстановить базу данных 7 до некоторого момента времени, потребуется grep через файлы FULL и DIFF и ручное применение этого sql.

Как мне поступить, чтобы иметь возможность восстановить один из предыдущих дампов DIFF в базе данных master?

Нужно ли мне выполнять резервное копирование в отдельные файлы базы данных, т.е.

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

скорее, чем..

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

Если я перейду к отдельным файлам mysqldump, что произойдет с двоичным журналом основных данных и нужно ли вообще устанавливать --master-data для дампов восстановления главного сервера?

Том Х
источник

Ответы:

7

Если вся ваша база данных использует только InnoDB, у меня есть хорошие новости.

Вы должны вывести всю базу данных параллельно с ведомого устройства.

Фактически, вы можете принудительно включить все базы данных в один и тот же момент времени.

Первое, что нужно помнить о подчиненном устройстве, это то, что не обязательно включать двоичное ведение журнала, если он не является ведущим для других подчиненных устройств.

Вы не можете использовать --master-dataопцию для параллельных дампов, потому что каждый дамп будет иметь различную позицию, записанную в строке 22 каждого файла дампов. Лучше записать последний файл журнала Мастера и позиционировать подчиненного, выполненного с помощью SHOW SLAVE STATUS\G. Таким образом, все базы данных имеют одинаковое положение на момент времени.

Вы можете собрать все базы данных и создать сценарий параллельного дампа всей базы данных.

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

Если баз данных слишком много, выведите их по 10 или 20 за раз следующим образом:

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

Если вам нужно восстановить одну таблицу, вы можете выполнять параллельное создание дампов по 20 таблиц одновременно в порядке размера.

Попробуй это:

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

Теперь, когда у вас есть сценарии для выгрузки баз данных или отдельных таблиц, вы можете загружать эти данные по своему усмотрению. Если вам нужно, чтобы SQL выполнялся из двоичных журналов на главном сервере, вы можете использовать mysqlbinlogи присвоить ему позицию datetime и вывести SQL в другие текстовые файлы. Вам просто нужно провести должную осмотрительность, чтобы найти необходимый объем данных по любым временным меткам бинарных журналов. Просто помните, что временная метка каждого двоичного журнала в ОС представляет тот последний раз, когда он был записан.

RolandoMySQLDBA
источник
блестящие ответы, спасибо. Я думаю, что наличие ведомого только для чтения на xfs дает мне множество вариантов, и ваши сценарии действительно помогли.
Том H
в сценарии, где мне нужно восстановить массивную таблицу для мастера из резервной копии с ведомого устройства. Мне просто нужно перестроить таблицу на ведущем устройстве, и все изменения реплицируются на ведомое устройство, даже если это 20 ГБ данных? Будет ли процесс: 1) отключить ключи, 2) удалить таблицу на главном и подчиненном устройстве 3) восстановить таблицу на главном устройстве 4) включить ключи - и будет ли мастер реплицировать все 20 ГБ на подчиненное устройство?
Том Х
Если эти базы данных НЕ являются innodb, могу ли я по-прежнему выводить их параллельно?
Том Х
Да, если вы: 1) запланированное время простоя, 2) запустить service mysql restart --skip-networking, 3) выполнить параллельный дамп, 4) запустить service mysql restart. Затем перезагрузите нужные вам таблицы.
RolandoMySQLDBA
предположительно, если цель перезапуска состояла в том, чтобы предотвратить запись сетевых соединений в базу данных, то я мог бы достичь того же эффекта, используя iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROPна eth0 и lo
Том Х