
万答,binlog解析出来的日志为何无法恢复
问题描述
问题来自一位群友,简单说就是用 mysqlbinlog 工具读取 binlog 欲进行恢复,却发现数据并没被恢复。
先一起来看下他是怎么做恢复的。
表中原来有几条数据,但不小心被清空了:
查看binlog event,有几条插入数据,最后还有一条 truncate table 的"误操作",现在想要把表数据恢复到误删数据前的状态。
运行下面的命令想要进行恢复数据,但发现不能正确恢复:
已经指定了读取binlog的位置是从4开始,到1512截止,因为再下一个event就是"误操作"了。之后查询 yejr.t1 表数据还是空的,没有被正确恢复。
问题解决
首先再次强调线上操作要非常谨慎,如果只是普通的DML操作,建议事先打开事务模式,这样万一误操作了还能执行 rollback 回滚。
但如果是DDL操作,则基本上只能依赖备份或者延迟从库,所以务必再三确认是在测试环境还是线上环境,以及即将执行的命令影响如何。
再回到问题本身。
在执行 mysqlbinlog 解析binlog并尝试恢复时,观察新的binlog,确认没有写入新数据,说明确实没执行恢复操作。
解析binlog查看,并没有类似 SET SQL_LOG_BIN=0 等忽略binlog的设置,而如果复制SQL指令执行出来手动执行,却是可以成功的。说明binlog本身没问题,是其他原因导致的。
再查看 binlog event 时注意到启用了 GTID 模式,在 GTID 模式下有个特点是要求 全局唯一。
除了GTID值持续递增之外,有个不容易注意的特点是,当事务GTID在已执行过的GTID集合(Executed_Gtid_Set)中的话,就不会再次被执行。假设以下几种场景:
● 假设当前Executed_Gtid_Set集合是 1-10,如果下一个GTID是5,它在这个范围内,则无法被执行。
● 假设当前Executed_Gtid_Set集合是 1-10, 20-30,如果下一个GTID是13,不在这个范围内,则可以被执行。
分别做个测试:
验证结果确实如上所说。
知道原因就好办了,查看 mysqlbinlog 的帮助文档,查看选项 --skip-gtids 的解释:
它可以使得解析出来的binlog event不再保留原来的 GTID 信息,这就可以当成新的 event 被执行了。所以,如果想要从binlog恢复数据,执行mysqlbinlog时,记得加上 --skip-gtids 选项。
全文完。
