Skip to content

综合实验二 MySQL 备份恢复与灾难恢复综合实战

综合实验二 MySQL 备份恢复与灾难恢复综合实战

Section titled “综合实验二 MySQL 备份恢复与灾难恢复综合实战”

🎯 本实验学习目标

  • 能使用 mysqldump 完成全库备份、单库备份和单表备份
  • 能模拟多种灾难场景并完成恢复操作
  • 能利用 binlog 完成时间点恢复(PITR)
  • 能设计并执行完整的备份策略方案

公司电商系统运行一段时间后,管理层意识到数据是核心资产。某天,发生了以下事件:

开发人员在调试时误删了 orders 表中的所有数据;紧接着,运维工程师发现有人用 DROP 命令删除了 products 表。公司需要你制定备份策略并能在各种灾难场景下恢复数据。


备份方式工具特点适用场景
全量逻辑备份mysqldump导出为 SQL 文件,可读性好小中型数据库(< 50GB)
全量物理备份xtrabackup / 数据文件复制直接复制数据文件,速度快大型数据库(> 50GB)
增量备份binlog只记录数据变更事件配合全量备份实现 PITR
Terminal window
# 在虚拟机中创建备份目录
sudo mkdir -p /backup/full
sudo mkdir -p /backup/binlog
sudo chown -R ly:ly /backup
sudo mysql
-- 确认 binlog 已开启
SHOW VARIABLES LIKE 'log_bin'; -- 应为 ON
SHOW VARIABLES LIKE 'binlog_format'; -- 应为 ROW
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds'; -- 应为 604800
-- 查看当前 binlog 文件和位置
SHOW MASTER STATUS;

这是最常用的备份方式——备份指定数据库的结构和数据:

Terminal window
# 备份 ecommerce 数据库
sudo mysqldump -u root -p123456 \
--databases ecommerce \
--single-transaction \
--routines \
--triggers \
--events \
--set-gtid-purged=OFF \
> /backup/full/ecommerce_full_$(date +%Y%m%d_%H%M%S).sql

参数说明:

参数含义
--databases ecommerce指定备份的数据库,输出中包含 CREATE DATABASEUSE 语句
--single-transactionInnoDB 一致性快照备份,不锁表(关键参数)
--routines包含存储过程和函数
--triggers包含触发器
--events包含定时事件
--set-gtid-purged=OFF不输出 GTID 信息(单机环境推荐)
Terminal window
# 备份所有数据库(系统库 + 业务库)
sudo mysqldump -u root -p123456 \
--all-databases \
--single-transaction \
--routines \
--triggers \
--events \
--set-gtid-purged=OFF \
> /backup/full/all_databases_$(date +%Y%m%d_%H%M%S).sql
Terminal window
# 只备份 orders 表
sudo mysqldump -u root -p123456 \
ecommerce orders \
--single-transaction \
--set-gtid-purged=OFF \
> /backup/full/ecommerce_orders_$(date +%Y%m%d_%H%M%S).sql
Terminal window
# 查看备份文件头部(前 30 行)
head -30 /backup/full/ecommerce_full_*.sql
# 查看备份文件大小
ls -lh /backup/full/
sudo mysql
-- 切换 binlog,让备份后的操作记录到新文件
FLUSH BINARY LOGS;
-- 记录当前 binlog 位置
SHOW MASTER STATUS;

输出类似:

+------------------+----------+
| File | Position |
+------------------+----------+
| mysql-bin.000003 | 157 |
+------------------+----------+

场景一 误删表数据(DELETE)——用 binlog 恢复

Section titled “场景一 误删表数据(DELETE)——用 binlog 恢复”
sudo mysql
USE ecommerce;
-- 记录当前数据量
SELECT COUNT(*) AS '恢复前订单数' FROM orders;
SELECT COUNT(*) AS '恢复前用户数' FROM users;
-- 正常业务操作:新增一笔订单
INSERT INTO orders (user_id, product_id, quantity, total_amount, order_status)
VALUES (2, 1, 1, 299.00, 0);
-- 记录这条正常操作的时间
SELECT NOW() AS '正常操作时间';
-- 灾难发生:误删 orders 表所有数据!
DELETE FROM orders;
SELECT COUNT(*) AS '误删后订单数' FROM orders; -- 结果:0

第 1 步:立即停止业务写入(课堂模拟中跳过,实际生产必须执行)

第 2 步:找到误操作在 binlog 中的位置

Terminal window
# 查看最新的 binlog 文件
sudo mysql -u root -p123456 -e "SHOW BINARY LOGS;"
# 在 binlog 中搜索 DELETE 操作
sudo mysqlbinlog --base64-output=DECODE-ROWS -v \
/var/lib/mysql/mysql-bin.000003 | grep -B 5 "DELETE FROM"

典型输出如下:

# at 316
#260603 10:09:21 server id 1 end_log_pos 382 CRC32 0xc46cad82 Table_map: `ecommerce`.`orders` mapped to number 92
# has_generated_invisible_primary_key=0
# at 382
#260603 10:09:21 server id 1 end_log_pos 525 CRC32 0x3ed3165c Delete_rows: table id 92 flags: STMT_END_F
### DELETE FROM `ecommerce`.`orders`
Terminal window
# 更精确地查看该位置附近的内容
sudo mysqlbinlog --base64-output=DECODE-ROWS -v \
--start-position=157 \
/var/lib/mysql/mysql-bin.000003 | less

找到 INSERT 事件的结束位置和 DELETE 事件的起始位置:

# at 380 ← INSERT(正常操作)
# at 316 ← DELETE 的 Table_map(误操作)← stop-position 用这个

第 3 步:从备份恢复到备份时刻的状态

Terminal window
# 先用备份恢复(恢复到备份时的数据状态)
sudo mysql -u root -p123456 < /backup/full/ecommerce_full_*.sql

第 4 步:回放 binlog 到误操作前

Terminal window
# 回放 binlog:从备份位置到误操作之前
sudo mysqlbinlog \
--start-position=157 \
--stop-position=580 \
--database=ecommerce \
/var/lib/mysql/mysql-bin.000003 | sudo mysql -u root -p123456

第 5 步:验证恢复结果

sudo mysql
USE ecommerce;
-- 验证数据恢复
SELECT COUNT(*) AS '恢复后订单数' FROM orders;
-- 应包含备份时的数据 + 误删前新增的那笔订单
-- 确认新增的订单已恢复
SELECT * FROM orders ORDER BY order_id DESC LIMIT 3;

场景二 误删表(DROP TABLE)——用全量备份 + binlog 恢复

Section titled “场景二 误删表(DROP TABLE)——用全量备份 + binlog 恢复”
sudo mysql
USE ecommerce;
-- 先补充一些新数据(模拟备份后的正常业务)
INSERT INTO products (name, category, price, stock) VALUES
('蓝牙耳机', '数码配件', 199.00, 80),
('充电宝', '数码配件', 129.00, 300);
-- 记录正常数据插入的时间
SELECT NOW() AS '正常操作时间';
-- 灾难发生:误执行了 DROP TABLE!
DROP TABLE products;

第 1 步:确认表已不存在

SHOW TABLES LIKE 'products';
-- 预期:空结果集

第 2 步:从备份恢复整个库

Terminal window
sudo mysql -u root -p123456 < /backup/full/ecommerce_full_*.sql

第 3 步:回放 binlog 恢复备份后的正常操作

Terminal window
# 从备份记录的位置开始,回放到 DROP 操作之前
# 假设 DROP 发生在位置 1200
sudo mysqlbinlog \
--start-position=157 \
--stop-position=1200 \
--database=ecommerce \
/var/lib/mysql/mysql-bin.000003 | sudo mysql -u root -p123456

第 4 步:验证恢复结果

sudo mysql
USE ecommerce;
-- 确认 products 表已恢复
SHOW TABLES;
-- 确认数据完整
SELECT COUNT(*) AS '恢复后商品数' FROM products;
SELECT * FROM products;
-- 确认备份后新增的商品也在
SELECT * FROM products WHERE name IN ('蓝牙耳机', '充电宝');

场景三 误删整个数据库——用全量备份恢复

Section titled “场景三 误删整个数据库——用全量备份恢复”
sudo mysql
-- 灾难发生:误删整个数据库
DROP DATABASE ecommerce;
-- 确认数据库已不存在
SHOW DATABASES LIKE 'ecommerce';
-- 预期:空结果集

第 1 步:从备份恢复

Terminal window
# 备份文件中包含 CREATE DATABASE 和 USE 语句,直接导入即可
sudo mysql -u root -p123456 < /backup/full/ecommerce_full_*.sql

第 2 步:验证恢复结果

sudo mysql
-- 确认数据库已恢复
SHOW DATABASES LIKE 'ecommerce';
USE ecommerce;
-- 确认所有表已恢复
SHOW TABLES;
-- 确认数据完整
SELECT COUNT(*) AS '用户数' FROM users;
SELECT COUNT(*) AS '商品数' FROM products;
SELECT COUNT(*) AS '订单数' FROM orders;
-- 抽样检查数据
SELECT * FROM orders;

4.1 在 Navicat 中备份 ecommerce 数据库

Section titled “4.1 在 Navicat 中备份 ecommerce 数据库”
  1. 打开 Navicat,连接到虚拟机 MySQL
  2. 右键 ecommerce 数据库 → 转储 SQL 文件结构和数据
  3. 保存为 D:\backup\ecommerce_navicat_$(日期).sql
  4. 等待导出完成
  1. 右键连接 → 新建数据库 → 名称:ecommerce_restore_test,字符集 utf8mb4
  2. 右键 ecommerce_restore_test运行 SQL 文件
  3. 选择刚才导出的 .sql 文件,执行
  4. 刷新数据库,验证表和数据:
SELECT COUNT(*) FROM ecommerce_restore_test.users;
SELECT COUNT(*) FROM ecommerce_restore_test.products;
SELECT COUNT(*) FROM ecommerce_restore_test.orders;
检查项验证方式预期结果
表结构完整SHOW TABLES;3 张表全部存在
数据行数一致COUNT(*) 逐表对比与源库完全一致
外键约束完整SHOW CREATE TABLE orders;包含 FOREIGN KEY 定义
数据内容正确抽样查询数据与源库一致

因素考虑点
RPO(恢复点目标)最多能接受丢失多长时间的数据?
RTO(恢复时间目标)从故障到恢复上线,最多允许花多长时间?
数据量数据量越大,全量备份耗时越长
业务写入频率写入越频繁,需要越频繁的增量备份
备份类型频率保留时间工具
全量备份每天凌晨 2:00保留 7 天mysqldump + cron
binlog持续记录保留 7 天MySQL 自动
备份类型频率保留时间工具
全量备份每周日凌晨 2:00保留 4 周mysqldump / xtrabackup
增量(binlog)持续记录保留 14 天MySQL 自动
mysql_backup.sh
#!/bin/bash
# 用途:每日自动备份 ecommerce 数据库
# 配置区
BACKUP_DIR="/backup/full"
DB_USER="root"
DB_PASS="123456"
DB_NAME="ecommerce"
DATE=$(date +%Y%m%d_%H%M%S)
KEEP_DAYS=7
# 创建备份
sudo mysqldump -u "$DB_USER" -p"$DB_PASS" \
--databases "$DB_NAME" \
--single-transaction \
--routines --triggers --events \
--set-gtid-purged=OFF \
> "$BACKUP_DIR/${DB_NAME}_${DATE}.sql"
# 检查备份是否成功
if [ $? -eq 0 ]; then
echo "[$(date)] 备份成功:${DB_NAME}_${DATE}.sql" >> /var/log/mysql_backup.log
else
echo "[$(date)] 备份失败!" >> /var/log/mysql_backup.log
fi
# 清理过期备份
find "$BACKUP_DIR" -name "${DB_NAME}_*.sql" -mtime +$KEEP_DAYS -delete

配置定时任务(课堂实操):

Terminal window
# 第 1 步:将脚本保存到固定位置
sudo mkdir -p /opt/scripts
sudo nano /opt/scripts/mysql_backup.sh
# 将上面的备份脚本内容粘贴进去,保存退出
# 第 2 步:赋予执行权限
sudo chmod +x /opt/scripts/mysql_backup.sh
# 第 3 步:手动测试一次(确认脚本能正常运行)
sudo /opt/scripts/mysql_backup.sh
ls -lh /backup/full/
# 第 4 步:配置 cron 定时任务
sudo crontab -e

在 crontab 编辑器中添加以下内容:

# 每天凌晨 2:00 自动备份 ecommerce 数据库
0 2 * * * /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

保存退出后验证 cron 是否生效:

Terminal window
# 查看当前用户的定时任务列表
sudo crontab -l
# 确认 cron 服务正在运行
sudo systemctl status cron

cron 时间格式速查:

字段含义取值范围
第 1 个 0分钟0 ~ 59
第 2 个 2小时0 ~ 23
第 3 个 *1 ~ 31
第 4 个 *1 ~ 12
第 5 个 *星期0 ~ 7(0 和 7 都是周日)

常见 cron 示例:

# 每天凌晨 2 点执行
0 2 * * *
# 每周日凌晨 3 点执行
0 3 * * 0
# 每 6 小时执行一次
0 */6 * * *
# 每月 1 日凌晨 1 点执行
0 1 1 * *

任务核心能力关键验证点
任务一:备份策略设计理解备份类型与适用场景能说出 RPO 含义
任务二:全量备份mysqldump 三种粒度备份3 个备份文件均已生成并验证
任务三:灾难恢复三种场景的恢复流程三种场景全部恢复成功
任务四:Navicat 备份恢复图形化备份还原备份还原验证通过
任务五:备份策略方案自动化备份方案设计脚本 + cron 可运行