备份与恢复策略
大约 12 分钟约 3703 字
备份与恢复策略
简介
数据库备份与恢复是保障数据安全的最后一道防线,完善的备份策略可以在硬件故障、人为误操作、数据损坏或自然灾害发生时最大限度地减少数据丢失。本文将系统介绍全量备份、增量备份、日志备份三种备份类型,RPO/RTO 的概念与设计,SQL Server 和 MySQL 的备份工具实践,以及灾难恢复方案的制定。
特点
备份类型与策略
三种备份类型
-- 备份类型对比
-- | 类型 | 说明 | 速度 | 存储占用 | 恢复速度 | 数据丢失风险 |
-- |-----------|--------------------------|-------|---------|-----------|-------------|
-- | 全量备份 | 备份所有数据 | 慢 | 大 | 快 | 取决于备份频率 |
-- | 增量备份 | 只备份上次备份后变化的数据 | 快 | 小 | 较慢 | 较低 |
-- | 日志备份 | 备份事务日志 | 最快 | 最小 | 最慢 | 最低 |
-- 备份策略组合(以 SQL Server 为例)
-- 策略一:简单恢复模式(适合非关键业务)
-- 每周全量 + 每日差异
-- RPO: 最多丢失 24 小时数据
-- 全量: 每周日凌晨
-- 差异: 每天凌晨
-- 策略二:完整恢复模式(适合关键业务)
-- 每周全量 + 每日差异 + 每小时日志
-- RPO: 最多丢失 1 小时数据(甚至更少)
-- 全量: 每周日凌晨
-- 差异: 每天凌晨
-- 日志: 每小时
-- 策略三:高安全模式(金融级)
-- 每日全量 + 每 6 小时差异 + 每 15 分钟日志
-- RPO: 最多丢失 15 分钟数据
-- 全量: 每天凌晨
-- 差异: 每 6 小时
-- 日志: 每 15 分钟备份策略设计
-- 备份策略设计需要考虑的因素
-- 1. 数据的重要程度
-- 2. 数据变化频率
-- 3. 可接受的数据丢失时间(RPO)
-- 4. 可接受的恢复时间(RTO)
-- 5. 存储空间和成本
-- RPO 与 RTO 说明
-- | 指标 | 全称 | 说明 |
-- |------|------------------------|--------------------------|
-- | RPO | Recovery Point Objective | 恢复点目标:可接受的最大数据丢失时间 |
-- | RTO | Recovery Time Objective | 恢复时间目标:从故障到恢复服务的最长时间 |
-- 不同业务的 RPO/RTO 要求
-- | 业务类型 | RPO | RTO | 推荐策略 |
-- |------------|-----------|-----------|----------------------|
-- | 金融交易 | < 1 分钟 | < 5 分钟 | 同步复制 + 日志备份 |
-- | 电商订单 | < 5 分钟 | < 30 分钟 | 日志备份 + 快速恢复 |
-- | 内容管理 | < 1 小时 | < 2 小时 | 差异备份 + 定期全量 |
-- | 日志分析 | < 24 小时 | < 8 小时 | 每日全量备份 |
-- | 开发测试 | < 1 周 | < 1 天 | 每周全量备份 |
-- 备份保留策略
-- | 备份类型 | 保留策略 |
-- |---------|----------------------------|
-- | 日志备份 | 保留 7 天 |
-- | 差异备份 | 保留 4 周 |
-- | 全量备份 | 最近 4 周每周一份 + 每月一份保留 1 年 |
-- | 年度备份 | 每年一份,保留 3-7 年(合规要求) |SQL Server 备份恢复
全量备份与恢复
-- 1. 创建全量备份
-- 备份到磁盘
BACKUP DATABASE [MyApp]
TO DISK = N'D:\Backup\MyApp_Full_20260412.bak'
WITH
FORMAT, -- 覆盖已有备份集
INIT, -- 覆盖已有备份媒体
NAME = N'MyApp-Full Backup',
COMPRESSION, -- 启用备份压缩
STATS = 10, -- 每 10% 显示进度
CHECKSUM, -- 启用校验
DESCRIPTION = N'每周全量备份 2026-04-12';
-- 备份到多个文件(提升备份速度)
BACKUP DATABASE [MyApp]
TO DISK = N'D:\Backup\MyApp_Full_1.bak',
DISK = N'E:\Backup\MyApp_Full_2.bak'
WITH FORMAT, COMPRESSION;
-- 备份到 URL(Azure Blob Storage)
BACKUP DATABASE [MyApp]
TO URL = N'https://myaccount.blob.core.windows.net/backups/MyApp_Full_20260412.bak'
WITH CREDENTIAL = N'AzureBackupCredential', COMPRESSION;
-- 2. 恢复全量备份
-- 先查看备份内容
RESTORE FILELISTONLY
FROM DISK = N'D:\Backup\MyApp_Full_20260412.bak';
RESTORE HEADERONLY
FROM DISK = N'D:\Backup\MyApp_Full_20260412.bak';
-- 恢复数据库
RESTORE DATABASE [MyApp]
FROM DISK = N'D:\Backup\MyApp_Full_20260412.bak'
WITH
MOVE N'MyApp' TO N'D:\Data\MyApp.mdf', -- 数据文件路径
MOVE N'MyApp_log' TO N'D:\Log\MyApp_log.ldf', -- 日志文件路径
REPLACE, -- 替换现有数据库
STATS = 10;
-- 恢复到新数据库名
RESTORE DATABASE [MyApp_Test]
FROM DISK = N'D:\Backup\MyApp_Full_20260412.bak'
WITH
MOVE N'MyApp' TO N'D:\Data\MyApp_Test.mdf',
MOVE N'MyApp_log' TO N'D:\Log\MyApp_Test_log.ldf';差异备份与日志备份
-- 1. 差异备份(只备份自上次全量备份后的变化)
BACKUP DATABASE [MyApp]
TO DISK = N'D:\Backup\MyApp_Diff_20260412.bak'
WITH
DIFFERENTIAL, -- 差异备份
COMPRESSION,
NAME = N'MyApp-Differential Backup';
-- 2. 事务日志备份
-- 前提:数据库必须处于完整恢复模式
ALTER DATABASE [MyApp] SET RECOVERY FULL;
-- 日志备份
BACKUP LOG [MyApp]
TO DISK = N'D:\Backup\MyApp_Log_20260412_1000.trn'
WITH
COMPRESSION,
NAME = N'MyApp-Log Backup';
-- 3. 完整恢复流程(全量 + 差异 + 日志链)
-- 步骤 1:恢复全量备份(NORECOVERY 模式)
RESTORE DATABASE [MyApp]
FROM DISK = N'D:\Backup\MyApp_Full_20260410.bak'
WITH NORECOVERY, REPLACE;
-- 步骤 2:恢复差异备份
RESTORE DATABASE [MyApp]
FROM DISK = N'D:\Backup\MyApp_Diff_20260412.bak'
WITH NORECOVERY;
-- 步骤 3:依次恢复日志备份
RESTORE LOG [MyApp]
FROM DISK = N'D:\Backup\MyApp_Log_20260412_0800.trn'
WITH NORECOVERY;
RESTORE LOG [MyApp]
FROM DISK = N'D:\Backup\MyApp_Log_20260412_0900.trn'
WITH NORECOVERY;
RESTORE LOG [MyApp]
FROM DISK = N'D:\Backup\MyApp_Log_20260412_1000.trn'
WITH RECOVERY; -- 最后一个用 RECOVERY
-- 4. 时间点恢复(Point-in-Time Recovery)
-- 恢复到 2026-04-12 09:30:00 的状态
RESTORE LOG [MyApp]
FROM DISK = N'D:\Backup\MyApp_Log_20260412_1000.trn'
WITH
STOPAT = N'2026-04-12 09:30:00',
RECOVERY;
-- 5. 自动化备份作业
-- 创建 SQL Server Agent Job
/*
USE msdb;
EXEC sp_add_job @job_name = N'Daily MyApp Backup';
EXEC sp_add_jobstep @job_name = N'Daily MyApp Backup',
@step_name = N'Full Backup',
@subsystem = N'TSQL',
@command = N'
DECLARE @path NVARCHAR(500);
SET @path = N''D:\Backup\MyApp_Full_'' +
CONVERT(NVARCHAR(8), GETDATE(), 112) + N''.bak'';
BACKUP DATABASE [MyApp] TO DISK = @path
WITH FORMAT, COMPRESSION, CHECKSUM;',
@database_name = N'master';
EXEC sp_add_schedule @schedule_name = N'Daily 2AM',
@freq_type = 4, -- 每天
@active_start_time = 20000; -- 凌晨 2:00
EXEC sp_attach_schedule @job_name = N'Daily MyApp Backup',
@schedule_name = N'Daily 2AM';
EXEC sp_add_jobserver @job_name = N'Daily MyApp Backup';
*/MySQL 备份恢复
mysqldump 逻辑备份
-- 1. mysqldump 全量备份
-- 备份单个数据库
-- mysqldump -u root -p --single-transaction --routines --triggers myapp > myapp_full_20260412.sql
-- 备份所有数据库
-- mysqldump -u root -p --all-databases --single-transaction > all_databases_20260412.sql
-- 常用参数说明
-- | 参数 | 说明 |
-- |-----------------------|-------------------------------|
-- | --single-transaction | InnoDB 一致性快照,不锁表 |
-- | --routines | 包含存储过程和函数 |
-- | --triggers | 包含触发器 |
-- | --events | 包含事件 |
-- | --master-data=2 | 记录 Binlog 位置(注释形式) |
-- | --flush-logs | 切换到新的 Binlog 文件 |
-- | --compress | 启用压缩传输 |
-- | --set-gtid-purged=OFF | GTID 环境下避免 GTID 冲突 |
-- 2. 备份特定表
-- mysqldump -u root -p myapp orders order_items > orders_backup.sql
-- 3. 只备份表结构
-- mysqldump -u root -p --no-data myapp > schema_only.sql
-- 4. 只备份数据
-- mysqldump -u root -p --no-create-info myapp > data_only.sql
-- 5. 恢复 mysqldump 备份
-- mysql -u root -p myapp < myapp_full_20260412.sql
-- 恢复时先关闭外键检查(提升恢复速度)
SET FOREIGN_KEY_CHECKS = 0;
SOURCE /path/to/myapp_full_20260412.sql;
SET FOREIGN_KEY_CHECKS = 1;MySQL 物理备份
# 1. Percona XtraBackup(热备份工具)
# 全量备份
xtrabackup --backup --target-dir=/backup/full_20260412 \
--user=root --password=secret
# 准备备份(使备份一致)
xtrabackup --prepare --target-dir=/backup/full_20260412
# 恢复备份(需要先停止 MySQL)
xtrabackup --copy-back --target-dir=/backup/full_20260412
chown -R mysql:mysql /var/lib/mysql
# 2. 增量备份
# 第一次增量(基于全量)
xtrabackup --backup --target-dir=/backup/incr_1 \
--incremental-basedir=/backup/full_20260412 \
--user=root --password=secret
# 第二次增量(基于上一次增量)
xtrabackup --backup --target-dir=/backup/incr_2 \
--incremental-basedir=/backup/incr_1 \
--user=root --password=secret
# 恢复增量备份
# 先准备全量
xtrabackup --prepare --apply-log-only \
--target-dir=/backup/full_20260412
# 合并第一次增量
xtrabackup --prepare --apply-log-only \
--target-dir=/backup/full_20260412 \
--incremental-dir=/backup/incr_1
# 合并第二次增量
xtrabackup --prepare \
--target-dir=/backup/full_20260412 \
--incremental-dir=/backup/incr_2
# 恢复
xtrabackup --copy-back --target-dir=/backup/full_20260412
# 3. 使用 Binlog 做时间点恢复
# 查看当前 Binlog 位置
mysql -e "SHOW MASTER STATUS;"
# 恢复到特定时间点
mysqlbinlog --stop-datetime="2026-04-12 09:30:00" \
/var/lib/mysql/mysql-bin.000123 | mysql -u root -p
# 恢复特定位置的 Binlog
mysqlbinlog --start-position=154 --stop-position=1024 \
/var/lib/mysql/mysql-bin.000123 | mysql -u root -pMySQL 自动备份脚本
#!/bin/bash
# MySQL 自动备份脚本
# 配置
DB_USER="backup_user"
DB_PASS="Backup@123456"
BACKUP_DIR="/data/backups/mysql"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
# 创建备份目录
mkdir -p ${BACKUP_DIR}/{full,daily}
# 全量备份(每周日执行)
if [ $(date +%u) -eq 7 ]; then
echo "[$(date)] 开始全量备份..."
xtrabackup --backup \
--target-dir=${BACKUP_DIR}/full/full_${DATE} \
--user=${DB_USER} --password=${DB_PASS} \
--compress --compress-threads=4 \
--parallel=4
echo "[$(date)] 全量备份完成: full_${DATE}"
# 清理过期的全量备份
find ${BACKUP_DIR}/full -maxdepth 1 -type d \
-mtime +${RETENTION_DAYS} -exec rm -rf {} \;
fi
# 每日逻辑备份(小数据量或特定表)
echo "[$(date)] 开始逻辑备份..."
mysqldump -u${DB_USER} -p${DB_PASS} \
--single-transaction --routines --triggers \
--all-databases | gzip > \
${BACKUP_DIR}/daily/all_db_${DATE}.sql.gz
echo "[$(date)] 逻辑备份完成: all_db_${DATE}.sql.gz"
# 清理过期的每日备份
find ${BACKUP_DIR}/daily -type f -mtime +${RETENTION_DAYS} -delete
# 上传到远程存储(如 OSS/S3)
# aws s3 cp ${BACKUP_DIR}/daily/all_db_${DATE}.sql.gz s3://my-backup/mysql/
echo "[$(date)] 备份流程完成"灾难恢复
灾难恢复方案
-- 灾难恢复等级
-- | 等级 | 方案 | RPO | RTO | 成本 |
-- |-----|----------------------------|-----------|------------|-------|
-- | 1 | 定时备份恢复 | 小时-天级 | 小时-天级 | 低 |
-- | 2 | 备份 + 日志链恢复 | 分钟级 | 小时级 | 中 |
-- | 3 | 主从复制 + 自动故障转移 | 秒级 | 分钟级 | 中 |
-- | 4 | 同城双活 | 接近零 | 秒级 | 高 |
-- | 5 | 异地双活 | 接近零 | 秒级 | 极高 |
-- 1. 定期验证备份可恢复性
-- SQL Server 验证备份
RESTORE VERIFYONLY
FROM DISK = N'D:\Backup\MyApp_Full_20260412.bak'
WITH CHECKSUM;
-- 定期恢复测试(建议每月至少一次)
-- 在测试环境执行完整的恢复流程
RESTORE DATABASE [MyApp_Test]
FROM DISK = N'D:\Backup\MyApp_Full_20260412.bak'
WITH
MOVE N'MyApp' TO N'T:\TestData\MyApp_Test.mdf',
MOVE N'MyApp_log' TO N'T:\TestData\MyApp_Test_log.ldf',
REPLACE;
-- 2. 异地备份策略
-- 备份数据需要至少存放在两个不同的物理位置
-- 方案:
-- a) 本地磁盘 + 网络存储(NAS/SAN)
-- b) 本地磁盘 + 云存储(OSS/S3/Azure Blob)
-- c) 本地 + 异地机房
-- 3. 灾难恢复演练清单
-- | 步骤 | 操作 | 预期结果 |
-- |-----|----------------------------|------------------|
-- | 1 | 确认最新备份文件存在 | 文件完整且可读 |
-- | 2 | 恢复全量备份 | 数据库可访问 |
-- | 3 | 恢复差异备份 | 数据更新到差异时间点 |
-- | 4 | 恢复日志备份链 | 数据更新到指定时间点 |
-- | 5 | 验证数据完整性 | 数据校验通过 |
-- | 6 | 验证应用程序连接 | 应用正常读写 |
-- | 7 | 记录恢复耗时 | 在 RTO 要求范围内 |数据损坏修复
-- SQL Server 数据损坏修复
-- 1. 检查数据库完整性
DBCC CHECKDB([MyApp]) WITH NO_INFOMSGS, ALL_ERRORMSGS;
-- 2. 检查特定表
DBCC CHECKTABLE('orders') WITH NO_INFOMSGS;
-- 3. 修复策略(按严重程度递增)
-- 允许数据丢失的最小修复
DBCC CHECKDB([MyApp], REPAIR_REBUILD);
-- 允许数据丢失的修复
ALTER DATABASE [MyApp] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DBCC CHECKDB([MyApp], REPAIR_ALLOW_DATA_LOSS);
ALTER DATABASE [MyApp] SET MULTI_USER;
-- MySQL 数据损坏修复
-- 1. 检查表
CHECK TABLE orders EXTENDED;
-- 2. 修复 MyISAM 表
REPAIR TABLE orders;
-- 3. InnoDB 恢复模式
-- 在 my.cnf 中配置
-- [mysqld]
-- innodb_force_recovery = 1 -- 从 1 开始,逐步增大
-- 级别说明:
-- 1 (SRV_FORCE_IGNORE_CORRUPT) — 忽略损坏页
-- 2 (SRV_FORCE_NO_BACKGROUND) — 阻止后台线程运行
-- 3 (SRV_FORCE_NO_TRX_UNDO) — 不执行事务回滚
-- 4 (SRV_FORCE_NO_IBUF_MERGE) — 不执行插入缓冲合并
-- 5 (SRV_FORCE_NO_UNDO_LOG_SCAN) — 不查看 undo log
-- 6 (SRV_FORCE_NO_LOG_REDO) — 不执行 redo log 前滚
-- 4. 从 InnoDB 损坏中恢复数据
-- SET innodb_force_recovery = 1;
-- mysqldump -u root -p --all-databases > recovery_dump.sql
-- 停止 MySQL,删除数据文件,重新初始化
-- 恢复 dump 文件优点
缺点
总结
数据库备份与恢复是数据安全体系中不可或缺的一环。全量备份提供完整的数据副本,增量备份减少备份时间和存储开销,日志备份实现时间点恢复能力。根据业务对 RPO 和 RTO 的要求,合理组合三种备份类型制定备份策略。SQL Server 和 MySQL 各自提供了完善的备份工具和恢复机制。定期验证备份的可恢复性、制定灾难恢复演练计划,是确保备份策略真正有效的关键。
关键知识点
- 数据库主题一定要同时看数据模型、读写模式和执行代价。
- 很多性能问题不是 SQL 语法问题,而是索引、统计信息、事务和数据分布问题。
- 高可用、备份、迁移和治理与查询优化同样重要。
- 先把数据模型、访问模式和执行代价绑定起来理解。
项目落地视角
- 所有优化前后都保留执行计划、样本 SQL 和关键指标对比。
- 上线前准备回滚脚本、备份点和校验方案。
- 把连接池、锁等待、慢查询和容量增长纳入日常巡检。
- 保留执行计划、样本 SQL、索引定义和优化前后指标。
常见误区
- 脱离真实数据分布讨论索引或分片。
- 只看单条 SQL,不看整条业务链路的事务和锁。
- 把测试环境结论直接等同于生产环境结论。
- 脱离真实数据分布设计索引。
进阶路线
- 继续向执行计划、存储引擎、复制机制和数据治理层深入。
- 把主题与 ORM、缓存、消息队列和归档策略联动起来思考。
- 沉淀成数据库设计规范、SQL 审核规则和变更流程。
- 继续深入存储引擎、复制机制、归档与冷热分层治理。
适用场景
- 当你准备把《备份与恢复策略》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合数据建模、查询优化、事务控制、高可用和迁移治理。
- 当系统开始遇到慢查询、锁冲突、热点数据或容量增长时,这类主题价值最高。
落地建议
- 先分析真实查询模式、数据量级和写入特征,再决定索引或分片策略。
- 所有优化结论都结合执行计划、样本数据和监控指标验证。
- 高风险操作前准备备份、回滚脚本与校验 SQL。
排错清单
- 先确认瓶颈在 CPU、I/O、锁等待、网络还是 SQL 本身。
- 检查执行计划是否走错索引、是否发生排序或全表扫描。
- 排查长事务、隐式类型转换、统计信息过期和参数嗅探。
复盘问题
- 如果把《备份与恢复策略》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《备份与恢复策略》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《备份与恢复策略》最大的收益和代价分别是什么?
