GTID 模式下的 PITR 注意点是什么
开启 GTID 后,二进制日志里每个事务都带 GTID 头,时间点恢复(PITR)的坐标系从「文件名 + 偏移量」变成「GTID 集合」。恢复时先把全备恢复到目标时刻之前的状态,再用 mysqlbinlog 重放备份位点到故障点之间的 binlog。GTID 环境最容易踩的坑是重复重放:目标实例已经执行过的 GTID,再灌一遍会直接报错。
基本信息
| 适用版本 | MySQL 5.7 / 8.0(GTID 默认开启于 8.0) |
|---|---|
| 定位参数 | gtid_executed(已执行集合)、gtid_purged(已清除集合) |
| 恢复流程 | 恢复全备 → 用备份自带 GTID 设置 gtid_purged → 重放 binlog |
| 常用工具 | mysqlbinlog --include-gtids / --exclude-gtids / --skip-gtids |
| 重放终止 | START REPLICA UNTIL SQL_BEFORE_GTIDS = '某 GTID' |
| 权限要求 | REPLICATION SLAVE / REPLICATION APPLIER 等 |
典型使用场景
- 误删数据后恢复到删除前一秒的状态,避开那条 DROP 或 DELETE
- 重建从库:把全备的 GTID 集合写到新实例的 gtid_purged 再开启复制
- 跨环境同步:把一段 binlog 重放到验证实例,复现线上问题
- 审计取证:按 GTID 区间提取特定时间段的事务列表
- 演练 PITR 流程:定期验证备份 + binlog 能否按预期恢复到目标时间点
GTID 定位与重放
GTID 定位与重放
# 看当前已执行的 GTID 集合与已清除集合
mysql -e "SELECT @@GLOBAL.gtid_executed, @@GLOBAL.gtid_purged;"
# 从备份位点开始重放 binlog,排除已执行过的 GTID 防止重复
mysqlbinlog --skip-gtids --start-position=1234 /data/binlog/mysql-bin.000123 \
| mysql -uroot -p
# 只重放指定 GTID 区间
mysqlbinlog --include-gtids='3a7f1e3b-1111-11ee-aaaa-bbbbccccdddd:4700-4710' \
/data/binlog/mysql-bin.000123 | mysql -uroot -p按 GTID 定位停止点
按 GTID 定位停止点
-- 复制场景:重放到某个 GTID 之前即停止
START REPLICA UNTIL SQL_BEFORE_GTIDS = '3a7f1e3b-1111-11ee-aaaa-bbbbccccdddd:4711';
-- 确认已经追平到目标位置
SELECT @@GLOBAL.gtid_executed;
SELECT WAIT_FOR_EXECUTED_GTID_SET('3a7f1e3b-1111-11ee-aaaa-bbbbccccdddd:4710', 60);
-- 恢复完成后检查复制是否正常
SHOW REPLICA STATUS\G重放方式对照
| 方式 | 适用情况 | 风险 |
|---|---|---|
| 带 GTID 头重放 | 目标实例干净或可跳过已执行事务 | GTID 已存在时报错中断,需先确认状态 |
| --skip-gtids 剥离 | 目标实例不打算参与复制、只当临时库 | gtid_executed 缺段,后续做主从会踩坑 |
| --exclude-gtids | 跳过特定事务(如误操作事务) | 跳过的事务带来的数据变化永久缺失 |
| UNTIL SQL_BEFORE_GTIDS | 复制重放到指定事务前停止 | 边界算错会多放或少放一个事务 |
用 --skip-gtids 重放会让目标实例的 gtid_executed 出现缺口:如果这个实例后续要加入复制拓扑,缺口会导致它无法被正确识别为已同步某些事务,切换或重建从库时问题才暴露。临时实例用完即弃可以用,正式节点不要用。
不要在重放前手工 SET @@SESSION.GTID_NEXT:binlog 文件里已经包含 GTID 头,重复设置会直接报错;正确做法是恢复全备后通过 gtid_purged 把备份已包含的集合告知实例,再重放之后的部分。