MySQL-16备份与恢复机制
·
MySQL备份与恢复机制
备份与恢复是数据库运维的核心技能,是保障数据安全和业务连续性的最后一道防线。MySQL提供了多种备份恢复机制,包括逻辑备份、物理备份、增量备份、点时间恢复等。本文将深入剖析MySQL的备份恢复原理、实现机制和最佳实践。
备份恢复机制概览
逻辑备份机制
mysqldump备份原理
mysqldump使用示例
-- 基本逻辑备份
mysqldump -u root -p --all-databases --single-transaction --master-data=2 --flush-logs --routines --triggers --events > full_backup.sql
-- 单数据库备份
mysqldump -u root -p production_db --single-transaction --quick --compress --order-by-primary > production_backup.sql
-- 指定表备份
mysqldump -u root -p production_db users orders products > tables_backup.sql
-- 只备份结构
mysqldump -u root -p --no-data --routines --triggers production_db > schema_backup.sql
-- 只备份数据
mysqldump -u root -p --no-create-info production_db > data_backup.sql
-- 条件备份
mysqldump -u root -p production_db users --where="created_at >= '2024-01-01'" > recent_users_backup.sql
mysqlpump并行备份
-- 并行逻辑备份
mysqlpump -u root -p --all-databases \
--default-parallelism=4 \
--parallel-schemas=2:db1,db2 \
--parallel-schemas=1:db3,db4 \
--compress-output=LZ4 \
--exclude-databases=test,mysql \
--exclude-tables=logs,sessions \
> parallel_backup.sql
-- 查看mysqlpump进度
mysql -u root -p -e "SHOW PROCESSLIST" | grep mysqlpump
-- 恢复并行备份
mysql -u root -p < parallel_backup.sql
物理备份机制
Percona XtraBackup原理
XtraBackup使用示例
# 全量物理备份
xtrabackup --backup --user=root --password=password --target-dir=/backup/full_backup --parallel=4 --compress --compress-threads=2
# 增量物理备份
xtrabackup --backup --user=root --password=password --target-dir=/backup/inc_backup --incremental-basedir=/backup/full_backup --parallel=4
# 压缩备份
xtrabackup --backup --user=root --password=password --target-dir=/backup/compressed_backup --compress --compress-threads=4 --compress-chunk-size=64K
# 流式备份到远程
xtrabackup --backup --user=root --password=password --stream=xbstream --target-dir=/tmp | ssh backup-server "cat > /backup/stream_backup.xbstream"
# 备份准备
xtrabackup --prepare --target-dir=/backup/full_backup
xtrabackup --prepare --apply-log-only --target-dir=/backup/full_backup --incremental-dir=/backup/inc_backup
# 查看备份信息
xtrabackup --stats --target-dir=/backup/full_backup
MySQL Enterprise Backup
-- MySQL Enterprise Backup (商业版)
-- 全量备份
mysqlbackup --user=root --password=password --backup-dir=/backup/enterprise_backup --with-timestamp backup
-- 增量备份
mysqlbackup --user=root --password=password --backup-dir=/backup/inc_backup --incremental --incremental-base=dir:/backup/full_backup backup
-- 压缩备份
mysqlbackup --user=root --password=password --backup-dir=/backup/compressed_backup --compress --compress-level=6 backup
-- 部分备份
mysqlbackup --user=root --password=password --backup-dir=/backup/partial_backup --include-tables="^production\." backup
-- 备份验证
mysqlbackup --backup-dir=/backup/full_backup validate
增量备份与二进制日志
基于二进制日志的增量备份
-- 启用二进制日志
[mysqld]
log-bin = mysql-bin
binlog-format = ROW
binlog-row-image = FULL
expire-logs-days = 7
max-binlog-size = 100M
-- 查看二进制日志状态
SHOW VARIABLES LIKE 'log_bin';
SHOW MASTER STATUS;
SHOW BINARY LOGS;
-- 备份二进制日志
mysqlbinlog --read-from-remote-server --host=master-host --user=repl --password=password --raw --stop-never mysql-bin.000001 > binlog_backup.sql
-- 查看二进制日志内容
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000001 | head -50
-- 基于时间点的二进制日志备份
mysqlbinlog --start-datetime="2024-01-15 10:00:00" --stop-datetime="2024-01-15 11:00:00" mysql-bin.000001 > time_range_binlog.sql
增量备份策略
点时间恢复 (PITR)
PITR实现原理
PITR操作示例
-- 场景:恢复到2024-01-15 10:30:00之前的状态
-- 步骤1: 找到最近的全量备份
ls -la /backup/full_backup_2024-01-14_000000/
-- 步骤2: 恢复全量备份
xtrabackup --copy-back --target-dir=/backup/full_backup_2024-01-14_000000/
chown -R mysql:mysql /var/lib/mysql/
systemctl start mysqld
-- 步骤3: 找到增量备份
ls -la /backup/inc_backup_2024-01-15_000000/
-- 步骤4: 应用增量备份
xtrabackup --prepare --apply-log-only --target-dir=/backup/full_backup_2024-01-14_000000/
xtrabackup --prepare --apply-log-only --target-dir=/backup/full_backup_2024-01-14_000000/ --incremental-dir=/backup/inc_backup_2024-01-15_000000/
-- 步骤5: 找到目标时间点的Binlog位置
mysqlbinlog --start-datetime="2024-01-15 00:00:00" --stop-datetime="2024-01-15 10:30:00" /var/log/mysql/mysql-bin.000001 | grep -E "at [0-9]+"
-- 步骤6: 应用二进制日志到目标时间点
mysqlbinlog --start-position=123456 --stop-datetime="2024-01-15 10:30:00" /var/log/mysql/mysql-bin.000001 /var/log/mysql/mysql-bin.000002 | mysql -u root -p
-- 步骤7: 验证恢复结果
mysql -u root -p -e "SELECT COUNT(*) FROM important_table WHERE created_at < '2024-01-15 10:30:00';"
备份验证与测试
备份完整性验证
-- 创建备份验证表
CREATE TABLE backup_verification (
id INT AUTO_INCREMENT PRIMARY KEY,
backup_type VARCHAR(50),
backup_file VARCHAR(255),
backup_size BIGINT,
backup_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
checksum VARCHAR(64),
verification_status ENUM('PENDING', 'SUCCESS', 'FAILED'),
verified_at TIMESTAMP NULL,
INDEX idx_backup_time (backup_time),
INDEX idx_verification_status (verification_status)
);
-- 备份验证存储过程
DELIMITER //
CREATE PROCEDURE verify_backup(
IN p_backup_type VARCHAR(50),
IN p_backup_file VARCHAR(255),
IN p_backup_size BIGINT,
IN p_checksum VARCHAR(64)
)
BEGIN
DECLARE v_verification_id INT;
DECLARE v_test_db VARCHAR(100);
DECLARE v_restore_result INT DEFAULT 0;
-- 记录备份信息
INSERT INTO backup_verification (backup_type, backup_file, backup_size, checksum, verification_status)
VALUES (p_backup_type, p_backup_file, p_backup_size, p_checksum, 'PENDING');
SET v_verification_id = LAST_INSERT_ID();
SET v_test_db = CONCAT('test_restore_', v_verification_id);
-- 创建测试数据库
SET @create_db_sql = CONCAT('CREATE DATABASE ', v_test_db);
PREPARE stmt FROM @create_db_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 尝试恢复备份到测试数据库
IF p_backup_type = 'LOGICAL' THEN
-- 逻辑备份恢复测试
SET @restore_sql = CONCAT('mysql -u root -p', @@global.mysql_root_password, ' ', v_test_db, ' < ', p_backup_file);
-- 这里需要调用系统命令,实际实现中需要使用外部脚本
SET v_restore_result = 1; -- 模拟成功
ELSEIF p_backup_type = 'PHYSICAL' THEN
-- 物理备份恢复测试
-- 使用xtrabackup进行恢复测试
SET v_restore_result = 1; -- 模拟成功
END IF;
-- 验证恢复结果
IF v_restore_result = 1 THEN
-- 检查表数量
SET @count_tables_sql = CONCAT('SELECT COUNT(*) INTO @table_count FROM information_schema.tables WHERE table_schema = ''', v_test_db, '''');
PREPARE stmt FROM @count_tables_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
IF @table_count > 0 THEN
UPDATE backup_verification
SET verification_status = 'SUCCESS', verified_at = NOW()
WHERE id = v_verification_id;
ELSE
UPDATE backup_verification
SET verification_status = 'FAILED', verified_at = NOW()
WHERE id = v_verification_id;
END IF;
ELSE
UPDATE backup_verification
SET verification_status = 'FAILED', verified_at = NOW()
WHERE id = v_verification_id;
END IF;
-- 清理测试数据库
SET @drop_db_sql = CONCAT('DROP DATABASE IF EXISTS ', v_test_db);
PREPARE stmt FROM @drop_db_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END//
DELIMITER ;
自动化备份方案
自动化备份脚本
#!/bin/bash
# MySQL自动化备份脚本
# 配置变量
MYSQL_USER="backup_user"
MYSQL_PASSWORD="backup_password"
BACKUP_DIR="/backup/mysql"
LOG_FILE="/var/log/mysql_backup.log"
RETENTION_DAYS=30
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
# 日志函数
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 发送通知函数
send_notification() {
local message=$1
local status=$2
if [ "$status" = "SUCCESS" ]; then
color="good"
else
color="danger"
fi
curl -X POST -H 'Content-type: application/json' \
--data "{
\"attachments\": [{
\"color\": \"$color\",
\"title\": \"MySQL Backup $status\",
\"text\": \"$message\",
\"footer\": \"Backup System\",
\"ts\": $(date +%s)
}]
}" $SLACK_WEBHOOK
}
# 检查备份目录
check_backup_directory() {
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p $BACKUP_DIR
log_message "Created backup directory: $BACKUP_DIR"
fi
}
# 全量备份函数
full_backup() {
local backup_date=$(date +%Y%m%d_%H%M%S)
local backup_file="$BACKUP_DIR/full_backup_$backup_date.sql.gz"
log_message "Starting full backup..."
# 执行全量备份
mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD \
--all-databases \
--single-transaction \
--master-data=2 \
--flush-logs \
--routines \
--triggers \
--events \
--hex-blob \
2>>$LOG_FILE | gzip > $backup_file
if [ $? -eq 0 ]; then
local backup_size=$(du -h $backup_file | cut -f1)
log_message "Full backup completed successfully. File: $backup_file, Size: $backup_size"
# 验证备份
if gunzip -t $backup_file 2>/dev/null; then
log_message "Backup file verification passed"
send_notification "Full backup completed successfully. File: $backup_file, Size: $backup_size" "SUCCESS"
return 0
else
log_message "Backup file verification failed"
send_notification "Full backup verification failed. File: $backup_file" "FAILED"
return 1
fi
else
log_message "Full backup failed"
send_notification "Full backup failed. Check log file: $LOG_FILE" "FAILED"
return 1
fi
}
# 增量备份函数
incremental_backup() {
local backup_date=$(date +%Y%m%d_%H%M%S)
local backup_file="$BACKUP_DIR/inc_backup_$backup_date.xbstream"
local last_backup_file="$BACKUP_DIR/last_backup_position"
log_message "Starting incremental backup..."
# 获取上次备份的位置
local last_binlog_file="mysql-bin.000001"
local last_binlog_pos=4
if [ -f "$last_backup_file" ]; then
last_binlog_file=$(head -1 $last_backup_file)
last_binlog_pos=$(tail -1 $last_backup_file)
fi
# 执行增量备份 (基于二进制日志)
mysqlbinlog --read-from-remote-server \
--host=localhost \
--user=$MYSQL_USER \
--password=$MYSQL_PASSWORD \
--raw \
--start-position=$last_binlog_pos \
--stop-never \
$last_binlog_file > $backup_file
if [ $? -eq 0 ]; then
# 更新备份位置
mysql -u $MYSQL_USER -p$MYSQL_PASSWORD -e "SHOW MASTER STATUS\G" | \
awk '/File:/ {print $2}' > $last_backup_file
mysql -u $MYSQL_USER -p$MYSQL_PASSWORD -e "SHOW MASTER STATUS\G" | \
awk '/Position:/ {print $2}' >> $last_backup_file
local backup_size=$(du -h $backup_file | cut -f1)
log_message "Incremental backup completed successfully. File: $backup_file, Size: $backup_size"
send_notification "Incremental backup completed successfully. File: $backup_file, Size: $backup_size" "SUCCESS"
return 0
else
log_message "Incremental backup failed"
send_notification "Incremental backup failed. Check log file: $LOG_FILE" "FAILED"
return 1
fi
}
# 清理旧备份
cleanup_old_backups() {
log_message "Cleaning up old backups (older than $RETENTION_DAYS days)..."
find $BACKUP_DIR -name "*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete
find $BACKUP_DIR -name "*.xbstream" -type f -mtime +$RETENTION_DAYS -delete
log_message "Old backup cleanup completed"
}
# 主函数
main() {
log_message "=== MySQL Backup Script Started ==="
check_backup_directory
# 根据星期几决定备份类型
day_of_week=$(date +%u)
if [ $day_of_week -eq 7 ]; then
# 周日执行全量备份
full_backup
else
# 其他时间执行增量备份
incremental_backup
fi
cleanup_old_backups
log_message "=== MySQL Backup Script Completed ==="
}
# 执行主函数
main
备份最佳实践
备份策略设计
备份检查清单
#!/bin/bash
# MySQL备份检查清单
echo "=== MySQL备份检查清单 ==="
# 1. 备份策略检查
echo "1. 备份策略检查"
echo "全量备份频率: $(crontab -l | grep -i full | wc -l) 个计划任务"
echo "增量备份频率: $(crontab -l | grep -i inc | wc -l) 个计划任务"
echo "备份保留策略: $(find /backup -name "*.sql*" -type f | wc -l) 个备份文件"
# 2. 备份完整性检查
echo "2. 备份完整性检查"
latest_backup=$(find /backup -name "*.sql.gz" -type f -exec ls -lt {} + | head -1 | awk '{print $9}')
if [ -n "$latest_backup" ]; then
echo "最新备份: $latest_backup"
if gunzip -t "$latest_backup" 2>/dev/null; then
echo "✓ 最新备份文件完整"
else
echo "✗ 最新备份文件损坏"
fi
fi
# 3. 备份恢复测试
echo "3. 备份恢复测试"
last_test=$(mysql -u root -p$MYSQL_ROOT_PASSWORD -e "
SELECT MAX(checked_at) FROM backup_verification WHERE verification_status = 'SUCCESS';
" -N 2>/dev/null)
echo "上次恢复测试: ${last_test:-'从未测试'}"
# 4. 二进制日志备份
echo "4. 二进制日志备份"
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "
SHOW BINARY LOGS;
" | tail -5
# 5. 备份存储检查
echo "5. 备份存储检查"
backup_size=$(du -sh /backup 2>/dev/null | cut -f1)
echo "备份总大小: $backup_size"
backup_age=$(find /backup -name "*.sql.gz" -type f -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f1)
echo "最新备份时间: $backup_age"
# 6. 备份监控检查
echo "6. 备份监控检查"
failed_backups=$(mysql -u root -p$MYSQL_ROOT_PASSWORD -e "
SELECT COUNT(*) FROM backup_verification WHERE verification_status = 'FAILED' AND checked_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);
" -N 2>/dev/null)
echo "近7天失败备份: ${failed_backups:-0}"
# 7. 灾难恢复能力
echo "7. 灾难恢复能力"
rto_target="4小时"
rpo_target="15分钟"
echo "RTO目标: $rto_target"
echo "RPO目标: $rpo_target"
# 8. 文档完整性
echo "8. 文档完整性"
if [ -f "/docs/backup_procedure.md" ]; then
echo "✓ 备份流程文档存在"
else
echo "✗ 备份流程文档缺失"
fi
if [ -f "/docs/recovery_procedure.md" ]; then
echo "✓ 恢复流程文档存在"
else
echo "✗ 恢复流程文档缺失"
fi
echo "=== 检查完成 ==="
通过实施这些备份恢复机制和最佳实践,可以构建一个可靠的数据保护体系,确保在各种故障场景下都能快速恢复数据,保障业务的连续性。
更多推荐
所有评论(0)