mysql全量、增量备份

1、概述

MySQL 里"增量备份"其实有两条路线:

  • 物理增量:用 Percona XtraBackup,基于 LSN 备份变化的数据页(大库首选)
  • 逻辑增量 :mysqldump 本身没有真增量,靠 全量 + binlog 回放 实现增量/时间点恢复(小库够用)

下面讲的是逻辑增量方式。

2、前置准备

2.1 开启 binlog(增量恢复必须)

my.cnf / my.ini

复制代码
[mysqld]
server-id = 1
log_bin = /var/lib/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
  • server-id:必须配置,binlog依赖server-id
  • binlog_format:生产强制ROW!statement容易数据不一致
  • expire_logs_days:数据库自动清理本地binlog,不要设置太大,防止磁盘打满

重启 MySQL 后确认:

复制代码
SHOW VARIABLES LIKE 'log_bin';
SHOW MASTER STATUS;

2.2 备份账号权限

复制代码
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'Backup@123';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT, PROCESS, SELECT, BACKUP_ADMIN ON *.* TO 'backup_user'@'localhost';

3、mysqldump 全量 + binlog 增量(适合 <50G 库)

3.1 全量备份

复制代码
mysqldump -ubackup_user -p \
  --single-transaction \
  --source-data=2 \
  --routines --triggers --events \
  --all-databases \
  --flush-logs \
  --default-character-set=utf8mb4 \
  > /backup/full_$(date +%F).sql
  • --single-transaction:核心!InnoDB 通过事务快照实现一致性,不加锁,业务正常读写;只对 InnoDB 生效,MyISAM 会失效
  • --source-data=2
    • 会在 sql 文件头部写入注释:-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=156;
    • =2 是注释形式,导入 sql 的时候不会执行;=1 是可执行语句,不要用 1
    • 这个位点就是我们后续 binlog 回放的起始位点,非常关键
  • --routines:导出存储过程、函数(很多脚本漏掉,恢复后存储过程丢失)
  • --triggers:导出触发器
  • --events:导出定时事件 event
  • --all-databases:导出所有库;如果只需要指定库,改成 --databases db1 db2
  • --flush-logs:dump 开始前,切割 binlog,生成一个新 binlog 文件
  • --default-character-set=utf8mb4:支持 emoji,避免字符集错乱

查看位点:

复制代码
grep "CHANGE MASTER" /backup/full_2026-11-11.sql
# 输出类似:mysql-bin.000123 位置 156

3.2 "增量备份"(其实是归档 binlog)

全量之后,新数据都在 binlog 里,start-position和位置用的上面的查看位点的信息:

复制代码
# 导出某个位点之后的 binlog
mysqlbinlog --start-position=156 \
  /var/lib/mysql/mysql-bin.000123 \
  > /backup/inc_$(date +%F_%H%M).sql

生产建议定时 FLUSH LOGS,把旧 binlog 拷贝走压缩归档。

3.3 恢复流程

复制代码
# 1. 停业务(避免新写入)
# 2. 建库清表或直接全量导入
mysql -uroot -p < /backup/full_2026-11-11.sql

# 3. 回放增量 binlog
mysql -uroot -p < /backup/inc_2026-11-11_1400.sql

# 4. 精确到误删前(可选 PITR)
mysqlbinlog --stop-datetime="2026-11-11 13:59:59" \
  /var/lib/mysql/mysql-bin.000124 | mysql -uroot -p

4、生产方案

4.1 目录结构

复制代码
/data/backup/
├── full/          # 全量
├── binlog/        # 增量
└── binlog.pos     # 记录上次 binlog 位点

4.2 全量备份脚本

/data/backup/full.sh

复制代码
# 每周日 02:00 执行: 0 2 * * 0 /data/backup/full.sh

USER="backup_user"
PASS="Backup@123"
DIR="/data/backup/full"
BINLOG_DIR="/data/backup/binlog"

# 1. 全量导出(--flush-logs 切一个新 binlog,之后的新数据都在新文件里)
mysqldump --no-defaults -u${USER} -p${PASS} \
  --single-transaction --source-data=2 --routines --triggers --events \
  --all-databases --flush-logs --set-gtid-purged=OFF \
  | gzip > ${DIR}/full_$(date +%F).sql.gz

if [ $? -ne 0 ]; then
  echo "$(date) FULL BACKUP FAILED" >> /data/backup/backup.log
  exit 1
fi

# 2. 记录本次全量对应的 binlog 位点(用于增量从这儿开始)
#    --source-data=2 写入了 sql 文件头,提取出来存好
gunzip -c ${DIR}/full_$(date +%F).sql.gz | grep "CHANGE MASTER" | head -1 > ${DIR}/full_$(date +%F).pos

# 3. 同时把这个位点作为增量备份的起点
gunzip -c ${DIR}/full_$(date +%F).sql.gz | grep "CHANGE MASTER" | head -1 > /data/backup/binlog.pos

# 4. 清理 7 天前的全量
find ${DIR} -name "full_*.sql.gz" -mtime +7 -delete
find ${DIR} -name "full_*.pos" -mtime +7 -delete

echo "$(date) full backup ok" >> /data/backup/backup.log
  • 示例脚本备份的是全部库,如果只备份指定库,需要修改脚本如:--databases test sys。

4.3 binlog 增量备份脚本

/data/backup/binlog.sh

复制代码
# 每 5 分钟执行: */5 * * * * /data/backup/binlog.sh

USER="backup_user"
PASS="Backup@123"
BINLOG_DIR="/usr/local/mysql"          # binlog 实际目录
BACKUP_DIR="/data/backup/binlog"
POS_FILE="/data/backup/binlog.pos"

# 读取上次位点
if [ -f "${POS_FILE}" ]; then
  LAST_FILE=$(awk -F"'" '{print $2}' ${POS_FILE})
  LAST_POS=$(awk -F'MASTER_LOG_POS=' '{print $2}' ${POS_FILE} | tr -d ';')
else
  echo "ERROR: no pos file, run full.sh first" >> /data/backup/backup.log
  exit 1
fi

# 获取当前位点
CURRENT=$(mysql --no-defaults -u${USER} -p${PASS} -N -e "SHOW MASTER STATUS" 2>/dev/null)
CUR_FILE=$(echo "${CURRENT}" | awk '{print $1}')
CUR_POS=$(echo "${CURRENT}" | awk '{print $2}')

# 位点没变就跳过
if [ "${LAST_FILE}" == "${CUR_FILE}" ] && [ "${LAST_POS}" == "${CUR_POS}" ]; then
  exit 0
fi

# 导出从上次位点到当前的 binlog
mysqlbinlog --no-defaults \
  --start-position=${LAST_POS} \
  ${BINLOG_DIR}/${LAST_FILE} \
  | gzip > ${BACKUP_DIR}/inc_$(date +%F_%H%M%S).sql.gz

if [ ${PIPESTATUS[0]} -ne 0 ]; then
  echo "$(date) binlog backup failed" >> /data/backup/backup.log
  exit 1
fi

# 更新位点
echo "CHANGE MASTER TO MASTER_LOG_FILE='${CUR_FILE}', MASTER_LOG_POS=${CUR_POS};" > ${POS_FILE}

# 清理 7 天前的增量
find ${BACKUP_DIR} -name "inc_*.sql.gz" -mtime +7 -delete

echo "$(date) binlog backup ok: ${LAST_FILE}:${LAST_POS} -> ${CUR_FILE}:${CUR_POS}" >> /data/backup/backup.log
  • 增量备份(binlog) → 永远是实例级,无法指定库。

4.4 恢复脚本

/data/backup/restore.sh

复制代码
# 用法: ./restore.sh

USER="root"
PASS="RootPass"
FULL_DIR="/data/backup/full"
BINLOG_DIR="/data/backup/binlog"

echo "=== 可用全量备份 ==="
ls -lt ${FULL_DIR}/full_*.sql.gz | head -5

read -p "输入要恢复的全量文件名: " FULL_FILE

# 1. 恢复全量
echo "恢复全量: ${FULL_FILE}"
gunzip -c ${FULL_DIR}/${FULL_FILE} | mysql --no-defaults -u${USER} -p${PASS}

# 2. 恢复增量(按时间顺序)
echo "恢复增量 binlog..."
for f in $(ls ${BINLOG_DIR}/inc_*.sql.gz 2>/dev/null | sort); do
  echo "  回放: $f"
  gunzip -c $f | mysql --no-defaults -u${USER} -p${PASS} --force
done

echo "恢复完成"
  • 示例脚本是恢复全部库,如果只恢复部分库,需要改参数mysqlbinlog 的 --database 参数,如

    mysqlbinlog --no-defaults
    --database=db1
    mysql-bin.000071
    | mysql --no-defaults -uroot -p

4.5 定时crontab

复制代码
crontab -e

0 2 * * 0 /data/backup/full.sh
*/5 * * * * /data/backup/binlog.sh
  • 全量:每周日 02:00 执行
  • 增量:每 5 分钟执行

4.6 部署 3 步搞定

复制代码
# 1. 创建目录
mkdir -p /data/backup/{full,binlog}

# 2. 上传 3 个脚本,改权限
chmod +x /data/backup/*.sh

# 3. 改脚本里的用户名密码
vi /data/backup/full.sh
vi /data/backup/binlog.sh
vi /data/backup/restore.sh

# 4. 先手动跑一次全量,确认没问题
/data/backup/full.sh

4.7 恢复时万一要精确到秒

复制代码
# 先恢复全量
gunzip -c /data/backup/full/full_2026-11-11.sql.gz | mysql -uroot -p

# 再回放 binlog 到误删前的那一刻
mysqlbinlog --no-defaults \
  --stop-datetime="2026-11-11 14:29:59" \
  /var/lib/mysql/mysql-bin.000071 \
  | mysql -uroot -p

4.8 总结

  • 全量 = mysqldump + --flush-logs 切 binlog;
  • 增量 = 从上次位点用 mysqlbinlog 捞变化;
  • 恢复 = 全量导入 + 增量回放。
相关推荐
AllData公司负责人8 小时前
AI大模型数据开发底座系列说明书,AllData集成Chat2DB开源项目建设AI 数据库分析底座,涵盖AI 洞察/对话SQL/智能视图!
数据库·人工智能·sql·开源·ai 洞察·对话sql
xixingzhe28 小时前
数据库备份的分类与特点
数据库
时间的拾荒人12 小时前
Redis 主从复制详解:配置实操 + 原理机制
数据库·redis·面试
隔窗听雨眠12 小时前
MySQL三表JOIN执行内核与优化器决策机制
数据库·mysql·sql优化
Decay__13 小时前
SQLServer 索引与 SQL 优化 —— 聚集索引、非聚集索引、覆盖索引、碎片维护与执行计划
运维·数据库·sql·mysql·架构
笃行35015 小时前
【金仓数据库产品体验官】订单增量同步实战:MERGE、OUTPUT 与 IDENTITY 的兼容验证
数据库
星恒随风18 小时前
MySQL 从零入门(六):复合查询详解——多表查询、自连接、子查询与 UNION
linux·服务器·数据库·mysql
无奈笑天下19 小时前
银河麒麟上lsblk命令教程详解
linux·运维·服务器·数据库
xiaoye-duck20 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型