This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
2026-05-21 12:20:51 +08:00

9.3 KiB
Raw Permalink Blame History

tags, create time
tags create time
MySQL
mysqldump
XtraBackup
PITR
备份恢复
2026-05-16 00:00

备份与恢复

概述

备份是数据安全最后一道防线。本章覆盖逻辑备份(mysqldump)、物理备份(Percona XtraBackup)、以及基于 binlog 的时间点恢复(PITR)三大核心方案。

备份策略全景

flowchart LR
    subgraph "逻辑备份"
        LD["mysqldump<br/>导出 SQL"]
        LF["全量 + 增量<br/>依赖 binlog"]
    end
    
    subgraph "物理备份"
        PD["Percona XtraBackup<br/>热拷贝ibd文件"]
        PF["压缩 + 加密<br/>支持部分备份"]
    end
    
    subgraph "选择指南"
        LS["数据量 < 50GB<br/>停机窗口可接受"]
        PS["数据量 > 50GB<br/>需要 0 停机"]
    end
    
    LD --> LS
    PD --> PS
    
    style LS fill:#00B6BC,color:#fff
    style PS fill:#00D866,color:#fff

mysqldump 逻辑备份

全量备份

# 最基础的全量备份
mysqldump -u root -p --all-databases > all_dbs_$(date +%F).sql

# 推荐的参数组合(保持一致性和完整性)
mysqldump \
  -u root -p \
  --single-transaction        # MVCC 快照,不锁表
  --flush-logs                # 切换 binlog,便于后续恢复
  --master-data=2             # 记录 binlog position(注释形式)
  --routines                  # 包含存储过程和函数
  --triggers                  # 包含触发器
  --events                    # 包含事件调度器
  --databases app_db report_db > backup_$(date +%F).sql

还原

# 全量还原
mysql -u root -p < backup_2026-05-16.sql

# 只还原某个表(先导出再导入)
mysqldump -u root -p app_db --table users > users.sql
mysql -u root -p app_db < users.sql

mysqldump 的优缺点

优点 缺点
简单可靠,几乎不会出错 大库慢(导入/导出)
文本格式,可读可编辑 导出的数据和原始可能有差异(如字符集转换)
自带权限和表结构定义 不支持增量备份
跨版本迁移方便 备份期间虽然有 --single-transaction,但 --flush-logs 仍需短暂锁表

Percona XtraBackup(物理备份)

全量备份

# 全量备份(热备,不停机)
xtrabackup --backup \
  --target-dir=/data/backups/full/ \
  --user=root --password=xxx \
  --parallel=4                    # 多线程并行拷贝
  
# 备份后的准备阶段(使备份可用于恢复)
xtrabackup --prepare --target-dir=/data/backups/full/

# 增量备份(基于上一次备份)
xtrabackup --backup \
  --target-dir=/data/backups/inc1/ \
  --incremental-basedir=/data/backups/full/ \
  --user=root --password=xxx

# 合并增量到全量(减少恢复时间)
# 先对全量做 prepare,只应用已提交的事务,不回滚未提交的
xtrabackup --prepare --target-dir=/data/backups/full/ --apply-only
# 再将增量备份合并进来
xtrabackup --prepare --target-dir=/data/backups/full/ --incremental-dir=/data/backups/inc1/

# 如果有多个增量层,依次合并
xtrabackup --prepare --target-dir=/data/backups/full/ --incremental-dir=/data/backups/inc2/

恢复

# 1. 停止 MySQL
systemctl stop mysqld

# 2. 清空数据目录(或用新目录)
rm -rf /var/lib/mysql/*

# 3. 拷贝备份数据
cp -a /data/backups/full/. /var/lib/mysql/

# 4. 设置权限
chown -R mysql:mysql /var/lib/mysql

# 5. 启动 MySQL
systemctl start mysqld

XtraBackup 的优缺点

优点 缺点
热备份:备份期间业务不受影响 学习曲线较陡
速度快:直接拷贝 ibd 文件 需要安装额外软件
支持增量备份 不能跨 major version(8.0→8.0)
恢复速度远快于 mysqldump 占用较多磁盘空间(物理拷贝)

PITR — 时间点恢复

结合全量备份 + binlog,可以将数据库恢复到任意精确时刻。

[!QUESTION] 思考:如果凌晨 3 点的备份完成时 binlog position 是 mysql-bin.000005:1234,而 10 点误操作发生在 mysql-bin.000006 中,该怎么办? 答案是:binlog 链不能断——从 mysql-bin.000005:1234 开始到当前为止的所有 binlog 文件都必须保留。任何缺失都会导致 PITR 失败。

timeline
    title PITR 恢复流程
    00:00 : 凌晨全量备份 (XtraBackup)
    06:00 : 应用正常运行
    10:00 : ⚠️ 误删表!DELETE FROM users;
    10:01 : 检测到异常,开始恢复
    恢复过程 : 1. 恢复全量备份到 00:00
             : 2. 重放 binlog 到 09:59:59
             : 3. 跳过误操作语句
             : 4. 恢复到 10:00 之前的状态
# 第一步:恢复全量备份
# (前面已讲过 XtraBackup 恢复步骤)

# 第二步:找到误操作的准确位置
# 方法 A:用时间定位(推荐,最直观)
mysqlbinlog --stop-datetime='2026-05-16 09:59:59' /var/lib/mysql/mysql-bin.000006 > safe_events.sql

# 方法 B:搜索误操作语句,获取 position
mysqlbinlog /var/lib/mysql/mysql-bin.000006 | grep -B5 "DROP DATABASE\|DELETE FROM users"
# 找到对应的 DELETE 所在事务的 stop_position,在此之前停止

# 第三步:重放 binlog 到误操作之前(基于 position)
mysqlbinlog \
  --start-position=1234 \
  --stop-position=4567 \
  /var/lib/mysql/mysql-bin.000005 > before_incident.sql

# 第四步:跳过误操作行,手动编辑 SQL 后重放其余部分
# 方法一:导出到文件后用 sed/grep 过滤掉误操作的 DDL/DML
mysqlbinlog /var/lib/mysql/mysql-bin.000005 > all_events.sql
# 用编辑器打开 all_events.sql,定位到误操作的 BEGIN/COMMIT 区间并删除

# 方法二:精确用 position 范围分段重放
mysqlbinlog \
  --stop-position=4567 \
  /var/lib/mysql/mysql-bin.000005 | mysql -u root -p  # 重放到误操作前

mysqlbinlog \
  --start-position=5000 \
  /var/lib/mysql/mysql-bin.000005 | mysql -u root -p  # 从安全点继续重放

# MySQL 8.0+ GTID 模式(推荐,更简洁)
# 包含 uuid 下 1~100 的 GTID,排除第 101 个事务(即误操作的那个)
mysqlbinlog \
  --include-gtids='uuid:1-100' \
  --exclude-gtids='uuid:101' \
  mysql-bin.000005 | mysql -u root -p

[!WARNING] PITR 的关键约束

  • 必须有完整的 binlog 链:全量备份时的 binlog position 之后所有的 binlog 都不能丢
  • binlog_format 必须是 ROW 或 MIXED:STATEMENT 模式下 PITR 不可靠(相同的 SQL 在不同上下文中可能产生不同结果)
  • GTID 需要 gtid_executed 一致:使用 --include-gtids / --exclude-gtids 要求服务端启用了 enforce_gtid_consistency=ON
  • 恢复到某个时间点会覆盖该时间点之后的所有数据:做好评估,建议先在测试库验证恢复流程

备份验证与自动化

[!QUESTION] 思考:如果一周后发生灾难,你发现昨晚的备份根本打不开——那时候还来得及补救吗? 未经测试的备份等于没有备份。定期验证是备份策略中最重要的环节。

验证方法

# mysqldump SQL 文件验证:在测试库导入一次
mysql -u root -p test_db < backup_latest.sql
# 检查关键表的数据量和行数是否符合预期

# XtraBackup 验证:prepare 阶段就是第一次验证
xtrabackup --prepare --target-dir=/data/backups/latest/
# prepare 成功 = 备份文件完整性合格
# 更进一步:恢复到从库或测试机做一次完整演练(至少每季度一次)

自动化方案

#!/bin/bash
# /opt/scripts/mysql-backup.sh — 每日备份脚本
set -euo pipefail

BACKUP_DIR="/data/backups"
DATE=$(date +%F)
RETENTION_DAYS=7

# 1. XtraBackup 全量备份
xtrabackup --backup \
  --target-dir="${BACKUP_DIR}/${DATE}/" \
  --user=backup_user --password=$(cat /etc/backup_pass) \
  --parallel=4

# 2. 压缩备份目录(节省磁盘空间)
tar czf "${BACKUP_DIR}/${DATE}.tar.gz" -C "${BACKUP_DIR}" "${DATE}"
rm -rf "${BACKUP_DIR}/${DATE}"

# 3. 清理超过保留期的旧备份
find "${BACKUP_DIR}" -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete

# 4. 备份元数据记录(方便追踪和恢复时定位)
echo "$(date +%F %T) | full | ${DATE} | OK" >> "${BACKUP_DIR}/backup.log"
# crontab -e — 每天凌晨 2 点执行
0 2 * * * /opt/scripts/mysql-backup.sh >> /var/log/mysql-backup-cron.log 2>&1

快速恢复清单

[!CHECKLIST] PITR 快速恢复步骤

  1. 确认误操作的准确时间
  2. 找到最新可用的全量备份及其 binlog position
  3. 停止应用写操作(防止二次损害)
  4. 恢复全量备份到干净目录
  5. 用 --stop-datetime 重放 binlog 到误操作前
  6. 启动 MySQL 并验证关键表数据
  7. 切换流量到新实例
  8. 通知相关人员,更新 incident 记录

备份频率建议

数据类型 全量备份频率 增量备份频率 binlog 留存
核心交易数据 每天一次 每小时 ≥ 7 天
用户数据 每天一次 每天 ≥ 7 天
日志/归档数据 每周一次 按需 按需
测试环境 按需 — 按需

关联笔记