故事开始
快要下班了,心情是这样的。
突然电话响了,一看电话号码是项目甲方负责人的号码
菊花一紧,难道出什么问题了,硬着头皮接通了电话。
@####@,你们程序怎么回事 ,某个业务的数据界面一条都查询不到了。。。。。
我们马上排查一下,看看那什么情况(心理活动:尼玛,尼玛,我怎么知道啊)???
哦豁、哦豁、数据库里也没了,用户做了一年的任务数据都没了,我尼玛!!!!
甲方要求今天必须恢复数据,什么问题导致的你们后面自己排查去。
好好好,是是是
(恢复数据不都是小菜一碟的事毕竟我们数据库每天凌晨有定时全量备份,也开了binlog日志的,哈哈,这难不倒我)
恢复数据没问题啊
binlog里面把删除语句找出来,逆向改成插入语句不就恢复了,这事不就欧了。
说干就干,先让公司现场运维同事帮忙把binlog拷贝出来
开始搞binlog,通过命令: mysqlbinlog --no-defaults -vv --base64-output=decode-rows --start-datetime='2024-12-30 16:49:35' --stop-datetime='2024-12-30 17:00:00' mysql-bin.000103 >outsql1.sql;找出对应时间点的语句删除。
找到删除语句还是很顺利,但是
binlog 中的删除语句只有被删除数据的ID,没有删除数据的详细数据,tmd 这怎么搞(后面再说原因,先恢复数据要紧)
没办法只能拷贝全量备份文件了
说明:
数据丢失的原因:程序缺陷导致,一个平常不用的功能,刚好年底了用到了
binlog里面为啥只有删除数据的ID没有详情:因为Binlog 格式设置的是“Mixed”
总结:
1、设Binlog模式要慎重,还得的按照自己项目实际情况去设置 binlog 类型,不然可能会对恢复数据造成麻烦。
binlog 有三种格式:
-
- Statement(Statement-Based Replication,SBR):每一条会修改数据的 SQL 都会记录在 binlog 中。
- Row(Row-Based Replication,RBR):不记录 SQL 语句上下文信息,仅保存哪条记录被修改。
- Mixed(Mixed-Based Replication,MBR):Statement 和 Row 的混合体。
Statement
Statement 模式只记录执行的 SQL,不需要记录每一行数据的变化,因此极大的减少了 binlog 的日志量,避免了大量的 IO 操作,提升了系统的性能。(比如update user set name="张三" where id >1 and id <10000,假设被修改的数据有2000条,那么Row的日志量就是2000条,而Statement只是这条sql语句一条日志而已,所以Statement的日志量相对Row会少很多)
但是,正是由于 Statement 模式只记录 SQL,而如果一些 SQL 中 包含了函数,那么可能会出现执行结果不一致的情况。比如说 uuid() 函数,每次执行的时候都会生成一个随机字符串,在 master 中记录了 uuid,当同步到 slave 之后,再次执行,就得到另外一个结果了。
所以使用 Statement 格式会出现一些数据一致性问题。
Row
从 MySQL5.1.5 版本开始,binlog 引入了 Row 格式,Row 格式不记录 SQL 语句上下文相关信息,仅仅只需要记录某一条记录被修改成什么样子了。
Row 格式的日志内容会非常清楚地记录下每一行数据修改的细节,这样就不会出现 Statement 中存在的那种数据无法被正常复制的情况。
不过 Row 格式也有一个很大的问题,那就是日志量太大了,特别是批量 update、整表 delete、alter 表等操作,由于要记录每一行数据的变化,此时会产生大量的日志,大量的日志也会带来 IO 性能问题。
Mixed
从 MySQL5.1.8 版开始,MySQL 又推出了 Mixed 格式,这种格式实际上就是 Statement 与 Row 的结合。
在 Mixed 模式下,系统会自动判断 该 用 Statement 还是 Row:一般的语句修改使用 Statement 格式保存 binlog;对于一些 Statement 无法准确完成主从复制的操作,则采用 Row 格式保存 binlog。
Mixed 模式中,MySQL 会根据执行的每一条具体的 SQL 语句来区别对待记录的日志格式,也就是在 Statement 和 Row 之间选择一种。
2、全量备份是必要的,这次就靠全量备份活过来了,binlog的增量备份也是很必要的可以尽量减少数据丢失,但是要注意binlog的模式设置。
3、cat testdb_all.sql |grep -E ‘INSERT INTO `personchangeinfo`’ > personchangeinfo1.sql ; 这个命令很实用,可以从大文件里面查找匹配内容并输出到新文件
4、用mysqldump 备份的文件,压缩比很可观的,别忘了压缩。