你想删库吗

2020-11-25 15:55:47 浏览数 (1)

戳这里,加关注哦~

删库跑路的案例不在少数,今年最出名的删库跑路当属微盟,造成公司市值蒸发几十亿,赔偿商家1.5亿元,最终在腾讯云的协助下经过7*24小时的不懈努力,最终找回全部数据。我们都知道,数据就是一个公司的“命根子”,无论什么时候,数据安全都是最重要的。所以我们今天来聊聊数据恢复的几种方式。以mysql为例。

binlog是二进制日志文件,用户记录用户对数据库的操作,各个从库的同步也是通过binlog,是非常重要的数据库日志文件,其他的关系型数据库的数据恢复也是大同小异的,例如Oracle数据库可以通过它的归档日志进行恢复。

我们该如何数据恢复?

具体如何恢复数据,要看使用的哪种备份方案,主流的备份方案主要有以下几种:

  1. 全量备份

数据量比较小,全量恢复比较快,例如每天晚上零点进行全量备份,如果想恢复20号以前的数据,直接把20号以前的备份全量恢复就行了

还有一种情况是恢复7号0:00到23:59的数据,这种情况就只能用binlog来恢复了。

  1. 全量 增量备份

全量 增量的备份方案适合数据量较大的数据库,节约磁盘空间,但是全量恢复较慢。如每月1号进行全量备份,后续的每天晚上零点进行增量备份,如果想恢复7号零点以前数据,就只需要恢复1号的全量数据,和2号到7号的增量备份。这种情况如果要恢复7号0:00到23:59的数据也是只能用binlog来恢复。

我们先不讨论每一种方案的效率问题,先看一下如果利用binlog进行恢复。

binlog的三种模式:

在MySQL5.7.7以前的版本默认模式是Statement Level,之后默认模式就是Row Level。

Statement Level:基于SQL语句复制的,只会讲SQL语句存储到日志中,因为这种模式只存储SQL,没有真正的数据,所以我们无法进行数据恢复。生产环境也一般不用这种模式。

Row Level:它是基于行的复制,并且会将每一条数据的变化记录到日志文件中,是没有sql语句的,可以解析出数据,一些生产环境是使用这种模式,但是它也有一定的缺点,比如记录数据时产生大佬的binlog,面对存储过程时可能出现数据不一致的情况。

Mixed:混合模式,默认情况下是Statement模式,某些情况下切换到Row模式,结合了Row Level和Statement Level的优点,同时binlog结构也更加复杂。

查看数据库采用的模式:

以MySQL5.7.21为例:

代码语言:javascript复制
mysql>show variables like 'binlog_format';

下边开始尝试用binlog进行数据解析和恢复了。

先建立一些基础数据:

代码语言:javascript复制
root@localhost(demo) 14:23:31> CREATE TABLE 't1' (
  -> 'id' int NOT NULL AUTO_INCREMENT,
    -> 'name' varchar(60) DEFAULT NULL,
    -> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSE=utf8;
Query OK,0 rows affected (0.02 sec)

root@localhost(demo) 14:23:31> insert into t1(name) values('demo1'),('demo2');
Query OK,2 rows affected (0.00 sec)
Records:2duplicates:0 Warnings:0

查找包含插入数据的时间(14:23:31)的binlog文件

代码语言:javascript复制
[root@localhost binlog]# ll mysql-bin.000009
-rw-r----- 1 mysql mysql  837Mar 2 14:23 mysql-bin.000009

我们可以看到是mysql-bin.000009文件,它是一个二进制文件,我们可以用MySQL自带的工具mysqlbinlog进行解析,看看具体的内容

代码语言:javascript复制
[root@10-0-4-162 binlog]# /usr/local/mysql/bin/mysqlbinlog --base64-output=decode-rows -v mysql-bin.000009

解析后删除无关的内容后,正向解析得到的sql和我们先前插入数据的sql一致

代码语言:javascript复制
......
# at 259
......
CREATE TABLE 't1' (
  'id' int NOT NULL AUTO_INCREMENT,
    'name' varchar(60) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSE=utf8
......
### INSERT INTO `demo`.`t1`
### SET
###    @1=1
###    @2='demo1'
###INSERT INTO `demo`.`t1`
###SET
###    @1=2
###    @2='demo2'
COMMIT/*!*/;
......

我们解析数据的目的是恢复数据,例如,将前面的insertSQL解析成deleteSQL语句,因为insert可能是误插入的数据,如果数据量较小可以手动删除,如果是生产环境,binlog文件可能非常大,解析后的SQL可能有千万行,手动修改不太现实,那么如何生成反向sql呢,我们将介绍两个数据恢复工具,binlog-rollback和MyFlash。

我们先用binlog-rollback试一下,其实这就是给perl脚本。

代码语言:javascript复制
[root@localhost ~]# perl binlog-rollback.pl -f '/u01/mysql/3306/log/binlog/mysql-bin.000009' -h 127.0.0.1 -u 'root' -p '1234' -P 3306 -i -o '/tmp/t.sql'

[root@localhost ~]# more /tmp/t.sql
DELETE FROM `demo`.`t1`WHERE 'id' = 2 AND `name` = 'demo2';
DELETE FROM `demo`.`t1`WHERE 'id' = 1 AND `name` = 'demo1';

可以看的我们之前insert的两行数据,这里解析成了delete了,达到了我们恢复数据的目的,当我们误删除数据时候,反解的SQL就成了insert,这样就可以达到数据恢复的目的。

我们再来试试MyFlash工具,这个工具在反解binlog的时候不需要用户名密码。同时我们也进行了查看发现确实由insert语句变成了delete。

但是这两种方式是有差别的,binlog-rollback生成sql,可读性更好,但是当数据量比较大的时候,MyFlash就比较快。

代码语言:javascript复制
[root@localhost MyFlash-master]# ./binary/flashback -- binlogFileNames=/u01/mysql/3306/log/binlog/mysql-bin.000009

[root@localhost MyFlash-master]# mysqlbinlog --base64-output=decode-rows -v binlog_output_base.flashback
......
### DELETE FROM `demo`.`t1`
### WHERE
###    @1=1
###    @2='demo1'
###DELETE FROM `demo`.`t1`
### WHERE
###    @1=2
###    @2='demo2'
......

总结:正向解析sql我们可以使用mysql自带的mysqlbinlog,反向解析我们可以使用binlog-rollback和MyFlash。

0 人点赞