返回 筑基・数据元府藏真

备份恢复与灾难恢复策略

博主
大约 12 分钟

备份恢复与灾难恢复策略

一、问题引入:误删数据的恐慌

1.1 真实案例:生产数据误删除事故

事故时间:周四下午3点
事故场景:新入职开发人员在生产环境执行测试脚本

事故经过:
┌─────────────────────────────────────────────────────────────┐
│ T1 15:00 - 开发人员连接生产数据库                             │
│     原意:在测试环境清理测试数据                               │
│     实际:连接字符串配置错误,连接到了生产库                   │
│                                                             │
│ T2 15:05 - 执行清理脚本                                       │
│     DELETE FROM orders WHERE created_at < '2024-01-01'       │
│     影响:删除了50万条历史订单数据                             │
│                                                             │
│ T3 15:10 - 用户反馈订单查询异常                               │
│     客服接到多个用户投诉无法查看历史订单                       │
│                                                             │
│ T4 15:15 - 发现问题,停止删除操作                             │
│     已删除数据:50万条订单记录                                 │
│     涉及用户:约10万人                                         │
│                                                             │
│ T5 15:20 - 开始评估恢复方案                                   │
│     方案1:从备份恢复 → 上次全量备份是昨天凌晨2点             │
│              意味着丢失13小时的数据                           │
│     方案2:使用Binlog闪回 → 需要解析大量Binlog                │
│                                                             │
│ T6 15:30 - 启动恢复流程                                       │
│     1. 找到昨天全量备份                                        │
│     2. 恢复全量备份到临时实例                                  │
│     3. 解析Binlog,提取15:00后的变更                           │
│     4. 合并数据,验证一致性                                    │
│                                                             │
│ T7 18:00 - 数据恢复完成                                       │
│     恢复时间:2小时45分钟                                      │
│     业务影响:订单服务不可用3小时                              │
│     直接损失:订单损失约200万,赔付用户100万                   │
└─────────────────────────────────────────────────────────────┘

事故反思:
1. 权限管理不当:开发人员有生产库DELETE权限
2. 备份策略不足:只有每日全量备份,没有实时Binlog备份
3. 恢复流程不熟悉:恢复耗时过长
4. 缺乏防误删机制:没有延迟从库、回收站等保护

改进措施:
1. 实施最小权限原则
2. 建立3-2-1备份策略
3. 部署延迟从库(1小时延迟)
4. 定期进行恢复演练
5. 实施操作审计和审批流程

1.2 数据丢失风险分析

数据丢失的常见原因:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  人为操作(40%)                                             │
│  - 误删除(DELETE/DROP/TRUNCATE)                            │
│  - 错误更新(UPDATE无WHERE条件)                             │
│  - 错误的DDL操作                                             │
│                                                              │
│  硬件故障(25%)                                             │
│  - 磁盘损坏                                                  │
│  - 服务器宕机                                                │
│  - 存储阵列故障                                              │
│                                                              │
│  软件故障(20%)                                             │
│  - 数据库Bug                                                 │
│  - 操作系统崩溃                                              │
│  - 应用Bug导致数据损坏                                       │
│                                                              │
│  灾难事件(10%)                                             │
│  - 机房火灾/水灾                                             │
│  - 地震等自然灾害                                            │
│  - 电力故障                                                  │
│                                                              │
│  安全事件(5%)                                              │
│  - 勒索软件加密                                              │
│  - 恶意删除                                                  │
│  - 数据泄露后删除                                            │
│                                                              │
└──────────────────────────────────────────────────────────────┘

二、备份策略设计

2.1 3-2-1备份原则

3-2-1备份原则:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  3 - 至少3份数据副本                                         │
│     - 1份生产数据                                            │
│     - 1份本地备份                                            │
│     - 1份异地备份                                            │
│                                                              │
│  2 - 使用2种不同存储介质                                     │
│     - 例如:磁盘 + 磁带/云存储                               │
│     - 防止单种介质故障                                       │
│                                                              │
│  1 - 至少1份异地备份                                         │
│     - 防止本地灾难(火灾、地震)                             │
│     - 建议距离>100公里                                       │
│                                                              │
└──────────────────────────────────────────────────────────────┘

备份类型选择:
┌──────────────┬────────────────────────────────────────────────┐
│ 备份类型     │ 特点                                           │
├──────────────┼────────────────────────────────────────────────┤
│ 全量备份     │ 完整数据,恢复简单,占用空间大,耗时长         │
│ 增量备份     │ 只备份变化数据,节省空间,恢复复杂             │
│ 差异备份     │ 备份自上次全量后的变化,平衡方案               │
│ Binlog备份   │ 记录所有变更,支持时间点恢复                   │
└──────────────┴────────────────────────────────────────────────┘

2.2 备份策略矩阵

数据重要性备份频率保留周期RTO目标RPO目标推荐方案
核心数据每日全量+实时Binlog30天1小时5分钟XtraBackup + Binlog
重要数据每日全量+每小时增量14天4小时1小时mysqldump + 增量
一般数据每周全量+每日增量7天8小时24小时逻辑备份
归档数据每月全量1年24小时1月冷备份

2.3 备份工具对比

工具类型速度恢复速度适用场景
mysqldump逻辑小数据量,跨版本恢复
XtraBackup物理大数据量,热备份
mydumper逻辑中等中等多线程逻辑备份
Clone Plugin物理MySQL 8.0+,实例克隆

三、备份实施详解

3.1 mysqldump逻辑备份

#!/bin/bash
# 全量备份脚本

BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="mydb"
RETENTION_DAYS=30

# 创建备份目录
mkdir -p ${BACKUP_DIR}/${DATE}

# 执行全量备份
mysqldump \
    --host=localhost \
    --user=backup \
    --password='backup_password' \
    --single-transaction \
    --routines \
    --triggers \
    --events \
    --master-data=2 \
    --all-databases \
    | gzip > ${BACKUP_DIR}/${DATE}/full_backup.sql.gz

# 备份配置文件和日志
cp /etc/my.cnf ${BACKUP_DIR}/${DATE}/
cp -r /var/log/mysql ${BACKUP_DIR}/${DATE}/

# 计算校验和
cd ${BACKUP_DIR}/${DATE}
md5sum full_backup.sql.gz > checksum.md5

# 清理旧备份
find ${BACKUP_DIR} -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \;

# 上传至异地存储
aws s3 sync ${BACKUP_DIR}/${DATE} s3://my-backup-bucket/mysql/${DATE}/

# 发送通知
echo "Backup completed: ${DATE}" | mail -s "MySQL Backup" admin@company.com
# 单表备份
mysqldump --single-transaction mydb orders > orders_backup.sql

# 仅备份结构
mysqldump --no-data mydb > schema_backup.sql

# 仅备份数据
mysqldump --no-create-info mydb > data_backup.sql

# 特定条件备份
mysqldump --where="created_at > '2024-01-01'" mydb orders > recent_orders.sql

# 并行备份(mydumper)
mydumper -u backup -p password -B mydb -o /backup/mydumper/ \
    --threads=4 \
    --compress \
    --triggers \
    --routines \
    --events

3.2 XtraBackup物理备份

#!/bin/bash
# XtraBackup全量备份脚本

BACKUP_DIR="/backup/xtrabackup"
DATE=$(date +%Y%m%d_%H%M%S)
FULL_BACKUP_DIR="${BACKUP_DIR}/full/${DATE}"

# 全量备份
xtrabackup \
    --backup \
    --target-dir=${FULL_BACKUP_DIR} \
    --user=backup \
    --password='backup_password' \
    --parallel=4 \
    --compress \
    --compress-threads=4

# 记录Binlog位置
cat ${FULL_BACKUP_DIR}/xtrabackup_binlog_info

# 准备备份(应用日志)
xtrabackup \
    --prepare \
    --target-dir=${FULL_BACKUP_DIR}

# 压缩备份
tar czvf ${FULL_BACKUP_DIR}.tar.gz -C ${FULL_BACKUP_DIR} .

# 上传至云存储
aws s3 cp ${FULL_BACKUP_DIR}.tar.gz s3://my-backup-bucket/xtrabackup/
# 增量备份
#!/bin/bash

BASE_DIR="/backup/xtrabackup/full/latest"
INCR_DIR="/backup/xtrabackup/incr/$(date +%Y%m%d_%H%M%S)"

# 基于全量备份的增量备份
xtrabackup \
    --backup \
    --target-dir=${INCR_DIR} \
    --incremental-basedir=${BASE_DIR} \
    --user=backup \
    --password='backup_password'

# 基于上次增量的增量备份
LAST_INCR=$(ls -td /backup/xtrabackup/incr/*/ | head -1)
xtrabackup \
    --backup \
    --target-dir=${INCR_DIR} \
    --incremental-basedir=${LAST_INCR} \
    --user=backup \
    --password='backup_password'

3.3 Binlog实时备份

#!/bin/bash
# Binlog实时备份脚本

BACKUP_DIR="/backup/binlog"
MYSQL_USER="backup"
MYSQL_PASS="backup_password"

# 获取当前Binlog文件和位置
CURRENT_LOG=$(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -e "SHOW MASTER STATUS\G" | grep File | awk '{print $2}')
CURRENT_POS=$(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -e "SHOW MASTER STATUS\G" | grep Position | awk '{print $2}')

echo "Current binlog: ${CURRENT_LOG} at position ${CURRENT_POS}"

# 使用mysqlbinlog实时备份
mysqlbinlog \
    --read-from-remote-server \
    --host=localhost \
    --user=${MYSQL_USER} \
    --password=${MYSQL_PASS} \
    --raw \
    --stop-never \
    --stop-never-slave-server-id=2000 \
    ${CURRENT_LOG} > ${BACKUP_DIR}/${CURRENT_LOG} &

# 或使用伪从库方式备份
cat > /etc/my.cnf.d/binlog-backup.cnf <<EOF
[mysqld]
server-id=2000
log_bin=/backup/binlog/mysql-bin
EOF

# 启动伪从库
mysql -u${MYSQL_USER} -p${MYSQL_PASS} -e "
CHANGE MASTER TO
    MASTER_HOST='master_host',
    MASTER_USER='repl',
    MASTER_PASSWORD='repl_password',
    MASTER_LOG_FILE='${CURRENT_LOG}',
    MASTER_LOG_POS=${CURRENT_POS};
START SLAVE SQL_THREAD;
"

四、恢复流程详解

4.1 全量恢复流程

#!/bin/bash
# XtraBackup全量恢复脚本

BACKUP_DIR="/backup/xtrabackup/full/20240115_020000"
DATA_DIR="/var/lib/mysql"

# 1. 停止MySQL
systemctl stop mysqld

# 2. 备份当前数据(可选)
mv ${DATA_DIR} ${DATA_DIR}.corrupt.$(date +%Y%m%d_%H%M%S)
mkdir -p ${DATA_DIR}

# 3. 准备备份(如果之前没准备过)
xtrabackup --prepare --target-dir=${BACKUP_DIR}

# 4. 恢复数据
xtrabackup \
    --copy-back \
    --target-dir=${BACKUP_DIR} \
    --datadir=${DATA_DIR}

# 5. 修改权限
chown -R mysql:mysql ${DATA_DIR}
chmod 750 ${DATA_DIR}

# 6. 启动MySQL
systemctl start mysqld

# 7. 验证数据
mysql -e "SELECT COUNT(*) FROM mydb.orders;"

4.2 时间点恢复(PITR)

#!/bin/bash
# 时间点恢复脚本

BACKUP_DIR="/backup/xtrabackup/full/latest"
BINLOG_DIR="/backup/binlog"
TARGET_TIME="2024-01-15 15:00:00"
DATA_DIR="/var/lib/mysql"

# 1. 恢复全量备份
systemctl stop mysqld
rm -rf ${DATA_DIR}
xtrabackup --copy-back --target-dir=${BACKUP_DIR} --datadir=${DATA_DIR}
chown -R mysql:mysql ${DATA_DIR}
systemctl start mysqld

# 2. 获取备份时的Binlog位置
BINLOG_FILE=$(cat ${BACKUP_DIR}/xtrabackup_binlog_info | awk '{print $1}')
BINLOG_POS=$(cat ${BACKUP_DIR}/xtrabackup_binlog_info | awk '{print $2}')

echo "Starting from binlog: ${BINLOG_FILE} at position ${BINLOG_POS}"

# 3. 应用Binlog到指定时间点
mysqlbinlog \
    --start-position=${BINLOG_POS} \
    --stop-datetime="${TARGET_TIME}" \
    ${BINLOG_DIR}/${BINLOG_FILE} \
    ${BINLOG_DIR}/mysql-bin.$((${BINLOG_FILE##*.} + 1)) \
    | mysql -u root -p

echo "Recovery completed to ${TARGET_TIME}"

4.3 误删除恢复(Binlog闪回)

# 使用binlog2sql进行闪回
# 安装:pip install binlog2sql

# 1. 解析Binlog生成回滚SQL
python binlog2sql.py \
    -h localhost \
    -u backup \
    -p 'backup_password' \
    -d mydb \
    -t orders \
    --start-file='mysql-bin.000001' \
    --start-datetime='2024-01-15 15:00:00' \
    --stop-datetime='2024-01-15 15:05:00' \
    -B > rollback.sql

# 2. 预览回滚SQL
cat rollback.sql

# 3. 执行回滚
mysql -u root -p mydb < rollback.sql

# 或使用MyFlash工具
# 安装MyFlash
wget https://github.com/Meituan-Dianping/MyFlash/archive/master.zip

# 生成回滚SQL
./flashback --binlogFileNames=/var/lib/mysql/mysql-bin.000001 \
    --start-datetime="2024-01-15 15:00:00" \
    --stop-datetime="2024-01-15 15:05:00" \
    --databaseNames=mydb \
    --tableNames=orders

# 应用回滚
mysqlbinlog binlog_output_base.flashback | mysql -u root -p

五、灾难恢复方案

5.1 RTO/RPO目标设定

RTO(恢复时间目标)vs RPO(恢复点目标):
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  时间轴:                                                    │
│                                                              │
│  故障发生                                                    │
│     │                                                        │
│     │<------- RPO ------->│                                  │
│     │                      │                                  │
│  最后备份                  故障点                            │
│     │                      │                                  │
│     │                      │<--------- RTO --------->│       │
│     │                      │                          │       │
│     │                      │                          ▼       │
│     │                      │                      服务恢复    │
│     │                      │                                  │
│     │<---------------- 数据丢失 ------------------->│         │
│                                                              │
│  RPO:可接受的数据丢失量(时间)                             │
│  RTO:可接受的恢复时间                                       │
│                                                              │
│  业务分级:                                                  │
│  ┌────────────┬─────────┬─────────┐                         │
│  │ 业务级别   │ RTO     │ RPO     │                         │
│  ├────────────┼─────────┼─────────┤                         │
│  │ 核心系统   │ 1小时   │ 5分钟   │                         │
│  │ 重要系统   │ 4小时   │ 1小时   │                         │
│  │ 一般系统   │ 24小时  │ 24小时  │                         │
│  └────────────┴─────────┴─────────┘                         │
│                                                              │
└──────────────────────────────────────────────────────────────┘

5.2 灾难恢复预案

# 数据库灾难恢复预案

## 1. 灾难分级

### P0 - 核心系统完全不可用
- 场景:主库宕机、数据中心故障
- 响应时间:5分钟内
- RTO:1小时
- RPO:5分钟

### P1 - 核心系统部分不可用
- 场景:主库性能严重下降、网络分区
- 响应时间:15分钟内
- RTO:2小时
- RPO:15分钟

### P2 - 非核心系统故障
- 场景:从库故障、备份失败
- 响应时间:1小时内
- RTO:4小时
- RPO:1小时

## 2. 恢复流程

### 主库故障恢复流程
1. **故障确认**(5分钟)
   - 确认主库确实不可用
   - 评估影响范围
   - 通知相关团队

2. **切换决策**(5分钟)
   - 尝试重启主库
   - 如无法恢复,启动切换流程

3. **主从切换**(10分钟)
   - 选择延迟最小的从库
   - 停止从库复制
   - 将从库提升为主库
   - 更新应用连接配置

4. **数据恢复**(30分钟)
   - 如需要,从备份恢复数据
   - 应用Binlog到目标时间点

5. **验证恢复**(10分钟)
   - 验证数据完整性
   - 验证应用连接
   - 恢复业务流量

### 数据误删除恢复流程
1. **停止写入**(立即)
   - 停止相关应用写入
   - 防止数据覆盖

2. **评估影响**(10分钟)
   - 确认删除的数据范围
   - 确认删除时间点

3. **选择恢复方案**
   - 方案A:延迟从库恢复(如果有)
   - 方案B:Binlog闪回
   - 方案C:备份恢复

4. **执行恢复**
   - 根据方案执行具体恢复操作

5. **数据验证**
   - 对比删除前后的数据量
   - 抽样验证数据正确性

## 3. 联系人清单

| 角色 | 姓名 | 电话 | 邮箱 |
|-----|------|------|------|
| DBA负责人 | 张三 | 13800138000 | zhangsan@company.com |
| 运维负责人 | 李四 | 13800138001 | lisi@company.com |
| 开发负责人 | 王五 | 13800138002 | wangwu@company.com |
| 业务负责人 | 赵六 | 13800138003 | zhaoliu@company.com |

## 4. 资源清单

### 备用服务器
- 服务器A:192.168.1.100(8核32G)
- 服务器B:192.168.1.101(8核32G)

### 存储资源
- 本地备份:/backup(10TB)
- 异地备份:s3://backup-bucket

### 工具
- XtraBackup:/usr/bin/xtrabackup
- mydumper:/usr/bin/mydumper
- binlog2sql:/opt/binlog2sql

5.3 自动化恢复脚本

#!/bin/bash
# 自动化故障切换脚本

MASTER_HOST="192.168.1.10"
SLAVE_HOSTS=("192.168.1.11" "192.168.1.12" "192.168.1.13")
VIP="192.168.1.100"

# 1. 检查主库状态
echo "Checking master status..."
mysql -h${MASTER_HOST} -e "SELECT 1" > /dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "Master is alive, no failover needed"
    exit 0
fi

echo "Master is down, starting failover..."

# 2. 找到延迟最小的从库
MIN_DELAY=999999
NEW_MASTER=""

for slave in ${SLAVE_HOSTS[@]}; do
    delay=$(mysql -h${slave} -e "SHOW SLAVE STATUS\G" | grep Seconds_Behind_Master | awk '{print $2}')
    if [ "$delay" != "NULL" ] && [ $delay -lt $MIN_DELAY ]; then
        MIN_DELAY=$delay
        NEW_MASTER=$slave
    fi
done

if [ -z "$NEW_MASTER" ]; then
    echo "No available slave found!"
    exit 1
fi

echo "Selected new master: ${NEW_MASTER} (delay: ${MIN_DELAY}s)"

# 3. 停止从库复制
mysql -h${NEW_MASTER} -e "STOP SLAVE; RESET SLAVE ALL;"

# 4. 提升为写库
mysql -h${NEW_MASTER} -e "SET GLOBAL read_only = OFF; SET GLOBAL super_read_only = OFF;"

# 5. 切换VIP
echo "Switching VIP to new master..."
ssh ${NEW_MASTER} "ip addr add ${VIP}/24 dev eth0"
ssh ${MASTER_HOST} "ip addr del ${VIP}/24 dev eth0" 2>/dev/null

# 6. 更新其他从库的主库指向
for slave in ${SLAVE_HOSTS[@]}; do
    if [ "$slave" != "$NEW_MASTER" ]; then
        mysql -h${slave} -e "STOP SLAVE;"
        mysql -h${slave} -e "CHANGE MASTER TO MASTER_HOST='${NEW_MASTER}', MASTER_AUTO_POSITION=1;"
        mysql -h${slave} -e "START SLAVE;"
    fi
done

# 7. 发送通知
echo "Failover completed. New master: ${NEW_MASTER}" | mail -s "MySQL Failover" admin@company.com

echo "Failover completed successfully!"

六、最佳实践与检查清单

6.1 备份检查清单

┌─────────────────────────────────────────────────────────────────────┐
│                      数据库备份检查清单                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  【日常检查】                                                       │
│  □ 1. 检查备份任务是否成功完成                                     │
│  □ 2. 检查备份文件大小是否合理                                     │
│  □ 3. 检查备份日志是否有错误                                       │
│  □ 4. 检查Binlog是否正常备份                                       │
│                                                                     │
│  【周检查】                                                         │
│  □ 1. 验证备份文件可恢复性                                         │
│  □ 2. 检查备份存储空间使用率                                       │
│  □ 3. 检查异地备份同步状态                                         │
│  □ 4. 更新恢复文档                                                 │
│                                                                     │
│  【月检查】                                                         │
│  □ 1. 执行完整恢复演练                                             │
│  □ 2. 测试Binlog闪回功能                                           │
│  □ 3. 检查备份保留策略执行情况                                     │
│  □ 4. 更新灾难恢复预案                                             │
│                                                                     │
│  【季度检查】                                                       │
│  □ 1. 跨机房恢复演练                                               │
│  □ 2. 评估RTO/RPO目标达成情况                                      │
│  □ 3. 优化备份策略                                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

6.2 常见错误与解决方案

错误后果解决方案
只有本地备份本地灾难时数据全失实施异地备份
从不测试恢复恢复时发现问题定期恢复演练
备份文件损坏无法恢复数据定期验证备份完整性
权限过大误操作风险最小权限原则
无Binlog备份无法时间点恢复实时Binlog备份
单点恢复恢复时间长并行恢复方案

系列上一篇数据库监控与性能分析体系

系列下一篇数据库安全与合规

知识点测试

读完文章了?来测试一下你对知识点的掌握程度吧!

评论区

使用 GitHub 账号登录后即可发表评论,支持 Markdown 格式。

如果评论系统无法加载,请确保:

  • 您的网络可以访问 GitHub
  • giscus GitHub App 已安装到仓库
  • 仓库已启用 Discussions 功能