传统的高可用架构是不能预防误删除数据的,因为主库的一个drop table命令,会通过binlog传给所有从库和级联从库,进而导致整个集群的实例都会执行这个命令。
为了找到解决误删数据库的更高效的方法,我们需要先对和MySQL相关的误删数据,做下分类:
- 使用delete语句误删数据行
- 使用drop table或者truncate table语句误删数据库
- 使用drop database语句误删数据库
- 使用rm命令误删整个MySQL实例
误删行
方案:使用delete语句误删了数据行,可以用Flashback工具通过闪回把数据恢复回来。
原理:修改binlog的内容,拿回原库重放。而能够使用这个方案的前提是,需要确保binlog_format=row和binlog_row_image=FULL。
具体:
- 对于insert语句,对应的binlog event类型是Write_rows event,把它改成Delete_rows event即可。
- 同理,对于delete语句,也是将Delete_rows event改为Write_rows event。
- 而如果是Update_rows的话,binlog里面记录了数据行修改前和修改后的值,对调这两行的位置即可。
而对于误删数据涉及到了多个事务的话,需要将事务的顺序调过来再执行。
当然恢复过程并不建议在主库上进行,而是恢复出一个备份,或者找一个从库作为临时库,在临时库上执行恢复操作,确认过数据无误后,在恢复回主库。(原因:一个在执行线上逻辑的主库,数据状态往往是有关联的。可能由于发现数据问题的实际晚了一点,就导致已经在之前误删的基础上,业务代码逻辑又继续修改了其他数据,如果这时进行数据恢复,未经确认,会导致出现对数据的二次破坏)
注意:不止要了解误删数据的事后处理方法,更重要的是做到事前预防。
建议:
1. 把sql_safe_updates参数设置成on,在delete或者update语句中写where,或者where条件不包含索引字段,这条语句就会报错。
2. 代码上线前,必须经过SQL审计
误删库/表
这种情况下,想要恢复数据就需要使用全量备份了,加增量日志的方式。这个方案要求线上定期的全量备份,并且实时备份binlog(因为对于drop/turncate table/database binlog记录的是statement格式,没法通过flasback进行恢复)
恢复数据的流程:
- 取最近一次全量备份(假设是一天一备,上次备份是当天0点)
- 用备份恢复出一个临时库
- 从日志备份里面,取出凌晨0点之后的日志
- 把这些日志,除了误删除数据的语句外,全部应用到临时库
说明:为了加速数据恢复,可以在mysqlbinlog加上-database,用来指定误删除表所在的库,但是这样还是不够快(1.误删表,不能指定解析一个表的日志;2.用mysqlbinlog解析出日志应用,应用日志的过程就只能是单线程)
误删库或表后,恢复数据的思路主要就是通过备份,再加上应用binlog的方式。最好把数据恢复功能做成自动化工具。
延迟复制备库
延迟复制备库是一种特殊的备库,通过CHANGE MASTER TO_DELAY = N命令,可以指定这个备库持续保持主库有N秒的延迟。
预防误删库表的方法
- 账号分离,权限控制
- 制定操作规范
- 定期给开发进行培训
- 搭建延迟备库
- 做好sql审计
- 做好备份