常在河边走,哪有不湿鞋。如果我们经常操作数据库,很有可能就会造成误操作,假如我们不幸误删了数据,有没有办法快速恢复呢?
这里,我们就以用的最多的mysql举例,聊聊如何快速恢复数据。mysql官方貌似并没有提供什么快速恢复数据的工具,业界倒是有很多和myql相关的快速恢复的工具,比如:binlog2sql,或者myflash。但是我看了看,都需要搞一些安装包,并且我发现有些工具已经不维护了,不清楚有没有啥问题,所以我的诉求是:
1)、工具要权威,并且持续迭代
2)、不要装一些和恢复数据没关系的包
基于以上想法,我找到了一篇国外老哥写的文章,原文链接,能看懂英文的,尽量看英文,原文写的很清晰。
我们这篇文章除了翻译一下国外老哥的文章外,还对其内容进行了补充,原文只是介绍了恢复工具的使用,略过了一些细节,对于一些刚入门的同学来说,需要了解一些前置知识的,所以就有了这篇文章。文章中,我从如何获取恢复工具,恢复前的准备工作,以及如何使用恢复工具进行恢复,进行了详细的解释,方便刚开始用mysql的同学学习。
下面我们开始进入正题
我们此次的mysql恢复数据操作要依赖mariadb的恢复工具mysqlbinlog,mariadb的mysqlbinlog有一个很炫的功能,flashback,官方介绍,flashback就是我们今天的主角,快速恢复数据就靠它了(据说flashback是阿里云的彭立勋开发的,然后贡献给了mariadb),目前flashback只支持DML操作,还不支持DDL。
1、准备工作
我本地用的是mac,装docker来测试的。
1)、获取mariadb的mysqlbinlog文件,拷贝到mysql对应目录下
首先,docker安装mysql 5.7.30。然后再用docker安装mariadb 10.2.40,从mariadb 10.2.40安装目录中的/usr/bin目录下将mysqlbinlog复制到本地,可以使用以下命令
docker cp a2c08aacaa83115877f:/usr/bin/mysqlbinlog /Users/test/mariadb/usr/bin/mysqlbinlog
然后再次利用docker cp命令将该mysqlbinlog拷贝到mysql 5.7.30安装目录的/usr/bin下,替换mysql的mysqlbinlog。
2)、测试数据
建立一个名为user_like的库,然后建立一张表t,并插入一条数据
CREATE TABLE `t` (`id` int(11) UNSIGNED NOT NULL,`c` int(11) UNSIGNED NULL DEFAULT NULL,`d` int(11) UNSIGNED NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE,INDEX `c`(`c`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;INSERT INTO `user_like`.`t` (`id`, `c`, `d`) VALUES (5, 5, 5);
2、开启binlog
数据恢复工作,基本都是基于binlog来做的,所以需要开启binlog
接下来
1、首先确保你开启了binlog日志
show variables like 'log_%';
如果未开启,需要在my.cnf中配置一下,比如:
log-bin = mysql-bin
server-id=171562767
binlog_format=row
3、关闭gtid的三个变量
如果我们的mysql是一个集群的话,恢复工作通常是在一台从机上。我们需要先关闭从机
//1、将这台机器从主从集群上摘下来
STOP SLAVE;//2、关闭gtid模式
SET GLOBAL gtid_mode = ON_PERMISSIVE;
SET GLOBAL enforce_gtid_consistency = OFF;//3、设置从机可写
SET GLOBAL read_only = OFF;
4、模拟数据误删除
删除一条数据
delete from t where id = 5;
5、通过mysqlbinlog查看误删除的语句
1)、查看目前mysql中有哪些binlog日志
SHOW BINARY LOGS
2)、查看binlog中的事件信息
show binlog events in 'mysql-bin.000013';
红框中的内容就是和我们这次delete语句相关的事件信息。从红框中可以看到我们此次删除操作涉及的表是:user_like.t,Delete_rows表明我们这是一条delete语句
3)、定位需要恢复的位点
事件表格中的第二列是事件的位点信息,可以看到位点是从154到395。
4)、通过位点查看删除的sql
我们利用mysqlbinlog看一下154到395都有哪些信息。
-vv 表明把所有信息都解析出来,-vv后面是binlog文件的位置,后面就是binlog的位点信息
mysqlbinlog -vv /var/lib/mysql/mysql-bin.000013 --start-position=154 --stop-position=395
通过mysqlbinlog的返回信息可以看到,我们执行了一条DELETE语句,删除了id=5的一行。
但是这里有一个问题,生产上,我们误执行了一条语句后,同时会有很多的其他语句也在执行,我们会看到很多的事件信息,此时不可能通过人工去筛选出来我们执行的误操作语句,我们只能知道,大概5分钟以前或者10分钟以前,误执行了一条语句。那这个时候,我们可以指定时间,比如下面的语句:
//查看过去半小时的binlog信息
mysqlbinlog -vv --start-datetime="$(date '+%F %T' -d 'now - 30 minutes')" --database=user_like --table=t /var/lib/mysql/mysql-bin.000013
6、通过mysqlbinlog查看闪回数据
通过mysqlbinlog,我们能够看到我们应该执行的恢复语句。如下:
//在末尾添加了--flashback参数,这个参数是闪回的关键
mysqlbinlog -vv --start-datetime="$(date '+%F %T' -d 'now - 30 minutes')" --database=user_like --table=t /var/lib/mysql/mysql-bin.000013 --flashback
如果是update语句,闪回会将set和where中的数据颠倒,输出一条update语句,比如:我们的一张表中有两个字段(f1,f2),其中有一行数据(2,2),假设我们误执行了
UPDATE a SET f2 = 10000 WHERE f1 = 2,然后再使用上面的闪回语功能查看闪回语句,就可以看到闪回语句是:
可以看到上述语句就是将我们的条件和更新数翻转了一下再执行
7、将闪回数据导出成binlog
mysqlbinlog --start-datetime="$(date '+%F %T' -d 'now - 2 hour')" --database=user_like --table=t /var/lib/mysql/mysql-bin.000013 --flashback > /usr/flashback.binlog
8、通过闪回的binlog恢复被误操作的数据
mysql -uroot -p111111 --init-command='SET sql_log_bin=0' user_like < /usr/local/flashback.binlog
我们需要另外弄一个mysql的实例,然后再创建一个user_like库,一张表 t,然后再执行上面的恢复操作,执行完后,检查无问题,可以导出执行sql到主库上执行。
9、如何按表恢复
在用备份恢复出临时实例之后,将这个临时实例设置成线上备库的从库,这样:在 start slave 之前,先通过执行change replication filter replicate_do_table = (tbl_name) 命令,就可以让临时库只同步误操作的表;这样做也可以用上并行复制技术,来加速整个数据恢复过程。