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

Tom*_*Tom 10 mysql innodb myisam replication mysqldump

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

我有 12 个数据库在主从复制配置中的 2 个 MySQL 5.0.77 服务器上运行。每天对只读从站进行完整转储,并且有可用的增量 SQL 转储,这些备份是异地备份,复制状态受到监控。

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

因此,如果主服务器完全故障,我可以中断复制并提升从服务器,我还可以选择重建新服务器并从越位完整备份进行配置,然后应用从从服务器每小时获取的差异。

但是我担心如何处理部分故障或单个数据库的故障。我可以想到 2 个很有可能的场景;

  1. 数据库 7(例如)损坏,继续处理一些请求,直到有人注意到它已损坏,或从日志文件中发出警报...
  2. 一些查询,如删除数据库、删除表、“更新哪里...”类型的查询会占用单个数据库或其中的某个子集。

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

要将数据库 7 恢复到某个时间点,需要通过 FULL 和 DIFF 文件进行 grep,并手动应用该 sql。

我应该如何继续以便能够恢复到以前的 DIFF 转储之一到主数据库?

我需要备份到单个数据库文件,即

mysqldump --databases "database1" | gzip > database1.sql.gz
mysqldump --databases "database2" | gzip > database2.sql.gz
mysqldump --databases "database3" | gzip > database3.sql.gz
Run Code Online (Sandbox Code Playgroud)

而不是..

mysqldump --master-data --lock--all-databases --all-databases | gzip > all-databases.sql.gz
Run Code Online (Sandbox Code Playgroud)

如果我使用单独的 mysqldump 文件,主数据二进制日志会发生什么,我什至应该为主服务器恢复转储设置 --master-data 吗?

Rol*_*DBA 7

如果你所有的数据库都只使用 InnoDB,我有一些好消息。

您应该从从站并行转储所有数据库。

事实上,您可以强制所有数据库进入相同的时间点。

关于从站要记住的第一件事是,如果它不是其他从站的主站,则不需要启用二进制日志记录。

您不能--master-data对并行转储使用选项,因为每个转储将在每个转储文件的第 22 行写入不同的位置。最好记录下 Master 的最后一个日志文件,并使用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;"
Run Code Online (Sandbox Code Playgroud)

如果数据库太多,一次转储 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;"
Run Code Online (Sandbox Code Playgroud)

如果您需要恢复单个表,您可以按大小顺序一次并行转储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;"
Run Code Online (Sandbox Code Playgroud)

现在您有了转储数据库或单个表的脚本,您可以自行决定加载该数据。如果您需要从 master 上的二进制日志中获取执行的 SQL,您可以使用mysqlbinlog并为其指定日期时间的位置并将 SQL 输出到其他文本文件。您只需执行尽职调查即可从二进制日志的任何时间戳中找到所需的数据量。请记住,操作系统中每个二进制日志的时间戳都代表它上次写入的时间。