← 返回 MYSQL 列表

日志体系与备份恢复

日志体系与备份恢复

一、Binlog(二进制日志)

1.1 Binlog 的作用

Binlog 是 MySQL Server 层的日志,记录所有数据变更操作(DDL 和 DML),用于:

  • 主从复制:从库读取主库 Binlog 同步数据
  • 数据恢复:通过 Binlog 进行时间点恢复(Point-in-Time Recovery)
  • 审计:记录数据变更历史

1.2 Binlog 的三种格式

格式 说明 优点 缺点
STATEMENT 记录原始 SQL 日志量小 某些函数(NOW()、UUID())在主从可能结果不同
ROW(默认) 记录每一行的变更 最精确,主从一致 日志量大
MIXED 自动选择 兼顾两者 复杂场景自动切换为 ROW
sql
-- 查看当前 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';

-- 设置 binlog 格式
SET GLOBAL binlog_format = 'ROW';

-- my.cnf 配置
[mysqld]
binlog_format = ROW
server_id = 1               -- 必须设置(主从复制需要)
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 7        -- 日志保留 7 天
max_binlog_size = 500M      -- 每个 binlog 文件最大 500MB

推荐使用 ROW 格式:虽然日志量大,但数据一致性最好,主从复制不会"跑偏"。

1.3 Binlog 的常用操作

sql
-- 查看 binlog 文件列表
SHOW BINARY LOGS;

-- 查看当前正在写入的 binlog
SHOW MASTER STATUS;

-- 查看 binlog 事件
SHOW BINLOG EVENTS IN 'mysql-bin.000001' LIMIT 10;

-- 通过 mysqlbinlog 工具查看 binlog 内容
-- 命令行:
mysqlbinlog --base64-output=decode-rows -vv /var/log/mysql/mysql-bin.000001

-- 刷新 binlog(生成新文件)
FLUSH LOGS;

-- 删除指定 binlog 之前的日志
PURGE BINARY LOGS TO 'mysql-bin.000010';

-- 删除所有 binlog 之前指定日期的
PURGE BINARY LOGS BEFORE '2024-06-01 00:00:00';

-- 设置 binlog 过期时间(推荐自动清理)
SET GLOBAL expire_logs_days = 7;

1.4 通过 Binlog 恢复数据

sql
-- 场景:误删了某张表的数据,需要通过 binlog 恢复

-- 步骤1:找到误操作的时间点和 binlog 位置
-- 查看 binlog 事件
SHOW BINLOG EVENTS IN 'mysql-bin.000005';

-- 假设找到了误删的 binlog 位置:从 position 5000 开始

-- 步骤2:将 binlog 导出为 SQL(排除误删的语句)
-- 导出到误删之前的 SQL
mysqlbinlog --start-position=1 --stop-position=5000 \
    /var/log/mysql/mysql-bin.000005 > recovery_before.sql

-- 步骤3:执行恢复
mysql -u root -p < recovery_before.sql

-- 更精确的做法:使用 mysqlbinlog 的时间点
mysqlbinlog --stop-datetime="2024-06-15 14:29:59" \
    /var/log/mysql/mysql-bin.000005 | mysql -u root -p

-- 跳过误删的语句然后继续后面的操作
mysqlbinlog --start-position=6000 \
    /var/log/mysql/mysql-bin.000005 | mysql -u root -p

1.5 Binlog 与 Redo Log 的区别

对比 Binlog Redo Log
所属层级 Server 层 InnoDB 引擎层
记录内容 逻辑 SQL/行变更 物理页修改
记录方式 追加写 循环写
用途 主从复制、数据恢复 崩溃恢复
清理方式 expire_logs_days 循环覆盖
两阶段提交 参与(保证一致性) 参与

二、备份方案

2.1 物理备份 vs 逻辑备份

对比 物理备份 逻辑备份
工具 xtrabackup(Percona) mysqldump
备份内容 数据文件 SQL 语句
备份速度 慢(大表尤其明显)
恢复速度
粒度 整个实例/库 表级别/行级别
适用场景 大数据量、全量备份 小数据量、迁移数据

2.2 mysqldump 逻辑备份

sql
-- 备份整个数据库
mysqldump -u root -p --databases mydb > mydb_backup.sql

-- 备份单表
mysqldump -u root -p mydb orders > orders_backup.sql

-- 备份多表
mysqldump -u root -p mydb orders users > mydb_part.sql

-- 常用参数
-- --single-transaction:InnoDB 一致性备份(不锁表)
-- --routines:导出存储过程和函数
-- --triggers:导出触发器
-- --master-data=2:记录 binlog 位置(注释形式)
mysqldump -u root -p \
    --single-transaction \
    --routines \
    --triggers \
    --master-data=2 \
    mydb > full_backup.sql

-- 恢复
mysql -u root -p mydb < full_backup.sql

-- 压缩备份
mysqldump -u root -p --single-transaction mydb | gzip > mydb_backup.sql.gz
gunzip < mydb_backup.sql.gz | mysql -u root -p mydb

2.3 Xtrabackup 物理备份

sql
-- Percona XtraBackup 安装后使用

-- 全量备份
xtrabackup --backup \
    --target-dir=/backup/mysql/full_20240601 \
    --user=root \
    --password=your_password

-- 准备备份(应用 redo log,使数据一致)
xtrabackup --prepare \
    --target-dir=/backup/mysql/full_20240601

-- 恢复备份
xtrabackup --copy-back \
    --target-dir=/backup/mysql/full_20240601 \
    --datadir=/var/lib/mysql

2.4 增量备份(Xtrabackup)

sql
-- 周一:全量备份
xtrabackup --backup --target-dir=/backup/mysql/full

-- 周二到周日:增量备份(基于前一天的增量)
xtrabackup --backup \
    --target-dir=/backup/mysql/incr_mon \
    --incremental-basedir=/backup/mysql/full

xtrabackup --backup \
    --target-dir=/backup/mysql/incr_tue \
    --incremental-basedir=/backup/mysql/incr_mon

-- 恢复时:准备全量 + 应用增量
xtrabackup --prepare --apply-log-only --target-dir=/backup/mysql/full
xtrabackup --prepare --apply-log-only \
    --target-dir=/backup/mysql/full \
    --incremental-dir=/backup/mysql/incr_mon
xtrabackup --prepare \
    --target-dir=/backup/mysql/full \
    --incremental-dir=/backup/mysql/incr_tue

-- copy-back 恢复
xtrabackup --copy-back --target-dir=/backup/mysql/full

2.5 定时备份脚本

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

BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d)
USER="root"
PASSWORD="your_password"

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

# 全量备份
mysqldump -u$USER -p$PASSWORD \
    --single-transaction \
    --all-databases \
    --master-data=2 \
    --routines \
    --triggers \
    | gzip > $BACKUP_DIR/full_$DATE/full_backup.sql.gz

# 删除 30 天前的备份
find $BACKUP_DIR -name "full_*" -mtime +30 -exec rm -rf {} \;

echo "Backup completed: $DATE"
bash
# crontab 定时任务
# 每天凌晨 2 点执行全量备份
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

三、数据误删恢复实操

3.1 完整恢复流程

sql
-- 场景:2024-06-15 14:30:00 误执行了 DROP TABLE orders

-- 前提:开启了 binlog

-- 步骤1:确认 binlog 文件和位置
SHOW MASTER STATUS;
-- 假设当前 binlog 文件:mysql-bin.000008

-- 步骤2:找到误操作前的 binlog 位置
SHOW BINLOG EVENTS IN 'mysql-bin.000008';
-- 找到含有 DROP TABLE 的事件,记录其 position

-- 步骤3:使用之前全量备份恢复
-- 先恢复最近一次全量备份(假设是 2024-06-15 凌晨 02:00)
mysql -u root -p < /backup/mysql/full_20240615/full_backup.sql

-- 步骤4:应用 binlog 增量(从备份完成到误操作前)
mysqlbinlog --start-datetime="2024-06-15 02:00:00" \
    --stop-datetime="2024-06-15 14:29:59" \
    mysql-bin.000008 mysql-bin.000007 | mysql -u root -p

-- 数据恢复到误删除前的状态!

3.2 误删数据恢复(没有备份的情况)

sql
-- 场景:误执行了 DELETE FROM orders WHERE status = 0(无 WHERE 条件)

-- 如果开启了 binlog 且格式为 ROW
-- 可以使用 mysqlbinlog 反解出原始数据

-- 步骤1:找到误操作对应的 binlog
mysqlbinlog --base64-output=decode-rows -vv \
    --start-datetime="2024-06-15 14:00:00" \
    mysql-bin.000008 > decoded.sql

-- 步骤2:从 ROW 格式的日志中找到 DELETE 事件的旧值
-- 文件中会有类似:
-- ### DELETE FROM `mydb`.`orders`
-- ### WHERE
-- ###   @1=1   -- id
-- ###   @2='20240101001'  -- order_no
-- ###   @3=100  -- user_id
-- ### ...

-- 步骤3:将 DELETE 转换为 INSERT
-- 可以写脚本将 DELETE 的旧值转为 INSERT 语句

-- 使用工具:mysqlbinlog 的 flashback 功能(第三方工具)
-- 或使用 binlog2sql 工具(Python)
pip install binlog2sql
binlog2sql --flashback \
    -h127.0.0.1 -P3306 -uroot -p'password' \
    -d mydb -t orders \
    --start-file='mysql-bin.000008' \
    --start-datetime='2024-06-15 14:00:00' \
    --stop-datetime='2024-06-15 14:30:00' > flashback.sql
mysql -u root -p < flashback.sql

3.3 误删表的恢复

sql
-- 场景:DROP TABLE orders;

-- 方案1:从全量备份恢复 + 增量 binlog
-- 同上 3.1

-- 方案2:如果开启了延迟复制
-- 有一台延迟 1 小时的从库
-- 1. 停止从库同步
STOP SLAVE;

-- 2. 查看延迟了多少
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: 3600

-- 3. 手动应用 binlog 到误操作前的位置
START SLAVE UNTIL ...

-- 4. 导出误删的表
mysqldump -u root -p mydb orders > orders_recovery.sql

-- 5. 恢复到主库
mysql -u root -p mydb < orders_recovery.sql

四、实战案例:完整备份恢复策略

sql
-- 备份策略设计:

-- 1. 物理备份(xtrabackup)
--    周日:全量备份
--    周一~周六:增量备份

-- 2. 逻辑备份(mysqldump)
--    每天凌晨:导出关键业务表

-- 3. Binlog 实时保存
--    定期将 binlog 同步到备份服务器

-- 恢复能力:
-- - 全量+增量+binlog:恢复到任意时间点
-- - RTO(恢复时间目标):2 小时内
-- - RPO(恢复点目标):最多丢失 5 分钟数据

-- 验证备份有效性:
-- 定期(每月)做一次恢复演练:
-- 1. 在一台测试实例上恢复全量备份
-- 2. 应用增量备份
-- 3. 应用 binlog 到指定时间点
-- 4. 验证数据完整性

总结

日志/备份 核心要点
Binlog 格式 ROW 为主,STATEMENT/MIXED 了解
Binlog 作用 主从复制、时间点恢复、审计
备份类型 物理备份(xtrabackup)快、逻辑备份(mysqldump)灵活
备份策略 全量+增量+binlog,定期验证恢复
恢复要点 全量恢复+binlog增量到误操作前
预防措施 延迟复制、权限控制、SQL审计