在繁忙的主从复制系统上恢复单个mysql数据库


10

在繁忙的复制系统中寻找一种策略或工具来将单个数据库恢复到某个时间点。

我有12个数据库以主从复制配置在2个MySQL 5.0.77服务器上运行。每天对只读从属服务器进行一次完全转储,并且有可用的增量SQL转储,这些备份不在现场并监视复制状态。

编辑:表是InnoDB和myISAM的混合,因此引擎特定的解决方案不可用。

因此,考虑到主服务器完全故障,我可以中断复制并升级从服务器,也可以选择重建新服务器并从越过FULL备份进行配置,然后应用每小时从从服务器获取的差异。

但是,我担心如何处理部分故障或单个数据库的故障。我可以想到两种可能的情况;

  1. 例如,数据库7损坏,继续处理一些请求,直到有人注意到它已损坏,或者来自日志文件的警报...
  2. 某些查询,例如放置数据库,放置表,“更新位置...”类型的查询,将使单个数据库或其中的某些子集失效。

目前,我有一堆完整的转储文件,例如FULL- $ DATE-all-databases.sql.gz文件,以及可以应用于DIFF- $ DATE-all-databases.sql.gz的差异文件

要将数据库7恢复到某个时间点,将需要通过FULL和DIFF文件进行grep,并手动应用该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吗?

Answers:


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,则可以使用mysqlbinlogdatetime并将其赋予位置,然后将SQL输出到其他文本文件。您只需执行尽职调查,即可从bnary日志具有的任何时间戳记中找到所需的数据量。只要记住,操作系统中每个二进制日志的时间戳都代表该日志的最后写入时间。


辉煌的答案thanx。我认为在xfs上具有只读从​​属会给我带来很多选择,并且您的脚本确实有所帮助。
Tom H,

在需要从从属服务器的备份中将大型表恢复到主服务器的情况下。我只需要在主数据库上重建表,并将所有更改复制到从数据库,即使那是20GB的数据呢?该过程是1)禁用密钥,2)将表放到主服务器和从属服务器上3)还原主服务器表4)启用密钥---并使主服务器将所有20GB复制到从属服务器吗?
Tom H

如果这些数据库不是innodb,是否仍可以并行转储它们?
汤姆H

是的,如果您1)安排停机时间,2)运行service mysql restart --skip-networking,3)执行并行转储,4)运行service mysql restart。然后重新加载所需的表。
RolandoMySQLDBA 2012年

大概是,如果重新启动的目的是防止网络连接写入数据库,那么我可以通过iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROP在eth0和lo上使用来实现相同的效果
Tom H
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.