什么是binlog
binlog是记录所有数据库表结构变更(例如CREATE、ALTER、DROP TABLE…)以及表数据修改(INSERT、UPDATE、DELETE…)的二进制日志。切记binlog中是不会记录select、show等对数据库数据库没有产生变更的操作的。
binlog的作用
- 数据复制
在MySQL主从架构中,从库的数据如何保持和主库的数据一致?其实就是利用的binlog,其实在实际的开发中,也有场景使用binlog来同步复制数据,比如将MySQL中的数据同步到ES中等; - 数据恢复
可以利用数据库备份+binlog恢复任意时间范围的数据; - 数据审计
用户可以通过二进制日志中的信息来进行审计,判断是否有对数据库进行注入攻击;
mysqlbinlog工具常用命令
常用参数 | 参数说明 |
-d ,--database=name | 根据指定库拆分binlog(拆分单表binlog可通过SQL关键字过滤) |
-r ,--result-file=name | 指定解析binlog输出SQL语句的文件 |
-R,--read-from-remote-server | 从mysql服务器读取binlog日志,是下面参数的别名 |
-j,--start-position=# | 读取binlog的起始位置点,#号是具体的位置点 |
-j,--start-position=# | 读取binlog的停止位置点,#号是具体的位置点 |
--start-datetime=name | 读取binlog的起始位置点,name是具体的时间,格式为:2004-12-25 11:25:26 |
--stop-datetime=name | 读取binlog的停止位置点,name是具体的时间,格式为:2004-12-25 11:25:26 |
--base64-output=decode-rows | 解析row级别binlog日志的方法,例如:mysqlbinlog --base64-output=decode-rows -v mysqlbin.000016 |
怎么利用binlog恢复误操作的数据
说一个实际的经历:前几天一个同事上线一个版本,上线后没多久就收到了用户的反馈,系统部分会员等级都没有了(上线版本中有个sql误将部分会员的会员等级给清除了),那个负责此次功能开发的同学第一时间找到了我,想让我帮忙恢复生产的数据。其实这样的时候,我之前的工作生涯中也遇到了两三次,但是基本上都是让运维去操作的,这次需要我亲自去处理。考虑到受影响的数据只有几千条,而且系统服务着几百万的用户,为了保证系统的稳定性和恢复数据的速度,我没有采用备份+binlog的方式进行恢复。我看了下sql的执行时间(2021-02-04 18:00:00),于是我去找个这个时间段的binlog文件,利用mysqlbinlog命令解析出来:
./mysqlbinlog --no-defaults -vv --base64-output=decode-rows --start-datetime='2021-02-04 17:59:50' --stop-datetime='2021-02-04 18:00:10' ~/Desktop/mysql-bin.000992 -r ~/Desktop/hotel.sql
得到这个文件后,记录格式如下:
### UPDATE `hub2`.`es_hotel_member`
### WHERE
### @1='1da3221a351911eb9d5eec0d9a37059e' /* VARSTRING(128) meta=128 nullable=0 is_null=0 */
### @2='34081119980622xxxx' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @3='王伟' /* VARSTRING(240) meta=240 nullable=1 is_null=0 */
### @4=1 /* INT meta=0 nullable=1 is_null=0 */
### @5='1' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @6='340811199806226319' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @7=NULL /* VARSTRING(80) meta=80 nullable=1 is_null=1 */
### @8='2021:02:20' /* DATE meta=0 nullable=1 is_null=0 */
### @9=0 /* TINYINT meta=0 nullable=1 is_null=0 */
### @10='1998:06:22' /* DATE meta=0 nullable=1 is_null=0 */
### @11=NULL /* DECIMAL(19,2) meta=4866 nullable=1 is_null=1 */
### @12=NULL /* DECIMAL(19,2) meta=4866 nullable=1 is_null=1 */
### @13=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
### @14='18016885237' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @15=NULL /* VARSTRING(1020) meta=1020 nullable=1 is_null=1 */
### @16=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### @17=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### @18=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### @19=NULL /* TINYINT meta=0 nullable=1 is_null=1 */
### @20=1 /* TINYINT meta=0 nullable=1 is_null=0 */
### @21=0 /* INT meta=0 nullable=1 is_null=0 */
### @22='37fd332cdeb811e987766c92bf5c82be' /* VARSTRING(128) meta=128 nullable=1 is_null=0 */
### @23=NULL /* VARSTRING(400) meta=400 nullable=1 is_null=1 */
### @24=NULL /* VARSTRING(400) meta=400 nullable=1 is_null=1 */
### @25=NULL /* VARSTRING(400) meta=400 nullable=1 is_null=1 */
### @26=NULL /* VARSTRING(200) meta=200 nullable=1 is_null=1 */
### @27=NULL /* VARSTRING(200) meta=200 nullable=1 is_null=1 */
### @28=NULL /* VARSTRING(4000) meta=4000 nullable=1 is_null=1 */
### @29='2020-12-03 11:39:15.260' /* DATETIME(3) meta=3 nullable=0 is_null=0 */
### @30='system' /* VARSTRING(128) meta=128 nullable=0 is_null=0 */
### @31='2020-12-03 11:39:15.260' /* DATETIME(3) meta=3 nullable=0 is_null=0 */
### @32='system' /* VARSTRING(128) meta=128 nullable=0 is_null=0 */
### @33=0 /* TINYINT meta=0 nullable=0 is_null=0 */
### SET
### @1='1da3221a351911eb9d5eec0d9a37059e' /* VARSTRING(128) meta=128 nullable=0 is_null=0 */
### @2='34081119980622xxxx' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @3='王伟' /* VARSTRING(240) meta=240 nullable=1 is_null=0 */
### @4=1 /* INT meta=0 nullable=1 is_null=0 */
### @5='1' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @6='340811199806226319' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @7=NULL /* VARSTRING(80) meta=80 nullable=1 is_null=1 */
### @8='2021:02:20' /* DATE meta=0 nullable=1 is_null=0 */
### @9=1 /* TINYINT meta=0 nullable=1 is_null=0 */
### @10='1998:06:22' /* DATE meta=0 nullable=1 is_null=0 */
### @11=NULL /* DECIMAL(19,2) meta=4866 nullable=1 is_null=1 */
### @12=NULL /* DECIMAL(19,2) meta=4866 nullable=1 is_null=1 */
### @13=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
### @14='18016885237' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
### @15=NULL /* VARSTRING(1020) meta=1020 nullable=1 is_null=1 */
### @16=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### @17=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### @18=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### @19=NULL /* TINYINT meta=0 nullable=1 is_null=1 */
### @20=0 /* TINYINT meta=0 nullable=1 is_null=0 */
### @21=0 /* INT meta=0 nullable=1 is_null=0 */
### @22='37fd332cdeb811e987766c92bf5c82be' /* VARSTRING(128) meta=128 nullable=1 is_null=0 */
### @23=NULL /* VARSTRING(400) meta=400 nullable=1 is_null=1 */
### @24=NULL /* VARSTRING(400) meta=400 nullable=1 is_null=1 */
### @25=NULL /* VARSTRING(400) meta=400 nullable=1 is_null=1 */
### @26=NULL /* VARSTRING(200) meta=200 nullable=1 is_null=1 */
### @27=NULL /* VARSTRING(200) meta=200 nullable=1 is_null=1 */
### @28=NULL /* VARSTRING(4000) meta=4000 nullable=1 is_null=1 */
### @29='2020-12-03 11:39:15.260' /* DATETIME(3) meta=3 nullable=0 is_null=0 */
### @30='system' /* VARSTRING(128) meta=128 nullable=0 is_null=0 */
### @31='2020-12-03 11:39:15.260' /* DATETIME(3) meta=3 nullable=0 is_null=0 */
### @32='system' /* VARSTRING(128) meta=128 nullable=0 is_null=0 */
### @33=0 /* TINYINT meta=0 nullable=0 is_null=0 */
至此,恢复数据就比较简单了,因为这里记录了sql之前前后数据的变化,只需要写段代码解析一下就可以了。