基于binlog恢复工具mysqlbinlog_flashback
简介
mysqlbinlog_back.py 是在线读取row格式的mysqld的binlog,然后生成反向的sql语句的工具。
一般用于数据恢复的目的。 所谓反向的sql语句就是如果是insert,则反向的sql为delete。
如果delete,反向的sql是insert,如果是update, 反向的sql还是update,但是update的值是原来的值。
这个项目需要安装
yum install python-pip
pip install pymysql
官方地址
https://github.com/58daojia-dba/mysqlbinlog_flashback
使用限制
1.支持mysql版本为MySQL 5.5 and 5.6.因为底层使用的是python-mysql-replication包。
2.数据库必须是row格式的。
3.反向生成的表必须有主键。
4.日志必须在主库存在
5.反向生成的mysql数据类型列出在下面。没有列出的类型没有经过严格的测试,也许有问题
6.支持的类型
允许解析的字段类型,不在里面的会报错
ALLOW_TYPE={ "varchar":True, "char":True, "datetime":True, "date":True, "time":True, "timestamp":True, "bigint":True, "mediumint":True, "smallint":True, "tinyint":True, "int":True, "smallint":True, "decimal":True, "float":True, "double":True, "longtext":True, "tinytext":True, "text":True, "mediumtext":True }
使用:
环境: 5.5.24
database:scheduler
table:user
表结构:
mysql> show create table user\G
*************************** 1. row ***************************
Table: user
Create Table: CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户唯一标志符 UID',
`username` varchar(64) DEFAULT NULL COMMENT '用户名,不区分大小写',
`email` varchar(128) DEFAULT NULL COMMENT '注册邮箱,不区分大小写',
`cell_phone` bigint(11) DEFAULT NULL COMMENT '手机号码',
`password` char(32) NOT NULL COMMENT '密码hash值',
`school_code` bigint(20) unsigned DEFAULT NULL COMMENT '学校代码',
`register_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '注册时间',
`usertype` int(5) NOT NULL DEFAULT '1' COMMENT '1为微信关注用户,2为微信登录app的用户,3为APP端微信登录的微信用户',
`state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1<0: UID是否有效 1<1: 是否设置用户名密码 1<2: 是否认证邮箱 1<3: 是否认证手机号码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
今天客服反馈有个用户使用手机号登陆不了,查看是由于程序BUG导致在用户登陆表里面的手机号是错误的值,
拿到用户真实的手机号之后,我们的初级DBA小明上线手一滑执行了
mysql> update user set cell_phone=15811111111;
Query OK, 10000 rows affected (0.08 sec)
Rows matched: 10000 Changed: 10000 Warnings: 0
当发现的时候已经来不及了,数据瞬间就被更改了
mysql> select * from user limit 10;
+-----+----------+-------+-------------+----------------------------------+-------------+---------------------+----------+-------+
| id | username | email | cell_phone | password | school_code | register_time | usertype | state |
+-----+----------+-------+-------------+----------------------------------+-------------+---------------------+----------+-------+
| 1 | NULL | NULL | 15811111111 | bc41014a6785b133a3c4fe29c1fc181e | 1 | 2014-02-26 18:09:44 | 3 | 1 |
| 664 | NULL | NULL | 15811111111 | 2b7dc70e9ef4aec3b36d9ed01f6c3917 | 1 | 2014-02-26 23:08:14 | 3 | 1 |
| 666 | NULL | NULL | 15811111111 | 19c0f7f7008765f55cfd64af4b7b7009 | 1 | 2014-02-26 23:08:15 | 3 | 1 |
| 670 | NULL | NULL | 15811111111 | 86b28ea44b6e4bc0b7d5c5010d288f1c | 1 | 2014-02-26 23:08:17 | 3 | 1 |
| 681 | NULL | NULL | 15811111111 | db79ffb99fafbf059d525c93e7c1e38c | 1 | 2014-02-26 23:08:26 | 1 | 1 |
| 682 | NULL | NULL | 15811111111 | aa237deac77a9b5c652e14b888aefccf | 1 | 2014-02-26 23:08:28 | 1 | 1 |
| 685 | NULL | NULL | 15811111111 | dae5acb6bd5de68011dd55f1b4d31303 | 1 | 2014-02-26 23:08:29 | 1 | 1 |
| 687 | NULL | NULL | 15811111111 | 05319ba2ec8767c80e68408eaeccd773 | 1 | 2014-02-26 23:08:31 | 1 | 1 |
| 689 | NULL | NULL | 15811111111 | 1dfda975919441990949918ceb25d7b6 | 1 | 2014-02-26 23:08:32 | 1 | 1 |
| 695 | NULL | NULL | 15811111111 | 8f13c73164f32794a2efb6f5b43194e8 | 1 | 2014-02-26 23:08:36 | 1 | 1 |
+-----+----------+-------+-------------+----------------------------------+-------------+---------------------+----------+-------+
这个时候记得赶紧加一个全局读锁,防止有新的写入发生 flush tables with read lock;
使用mysqlbinlog_back.py工具进行回滚
python mysqlbinlog_back.py --help 查看下参数使用说明
mysqlbinlog -v -v --base64-output=decode-rows mysql-bin.000006 >6.sql、
# at 700692
#170221 15:26:27 server id 1003306 end_log_pos 700765 Query thread_id=83 exec_time=0 error_code=0
SET TIMESTAMP=1487661987/*!*/;
BEGIN
### UPDATE scheduler.user
### WHERE
### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @2=NULL /* LONGINT meta=192 nullable=1 is_null=1 */
### @3=NULL /* LONGINT meta=384 nullable=1 is_null=1 */
### @4=13930226699 /* LONGINT meta=0 nullable=1 is_null=0 */
### @5='bc41014a6785b133a3c4fe29c1fc181e' /* STRING(96) meta=65120 nullable=0 is_null=0 */
### @6=1 /* LONGINT meta=0 nullable=1 is_null=0 */
### @7=1393409384 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
### @8=3 /* INT meta=0 nullable=0 is_null=0 */
### @9=1 /* TINYINT meta=0 nullable=0 is_null=0 */
### SET
### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @2=NULL /* LONGINT meta=192 nullable=1 is_null=1 */
### @3=NULL /* LONGINT meta=384 nullable=1 is_null=1 */
### @4=15811111111 /* LONGINT meta=0 nullable=1 is_null=0 */
### @5='bc41014a6785b133a3c4fe29c1fc181e' /* STRING(96) meta=65120 nullable=0 is_null=0 */
### @6=1 /* LONGINT meta=0 nullable=1 is_null=0 */
### @7=1393409384 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
### @8=3 /* INT meta=0 nullable=0 is_null=0 */
### @9=1 /* TINYINT meta=0 nullable=0 is_null=0 */
在binlog里面找到刚刚的update数据,开始进行回滚
python mysqlbinlog_back.py --host="127.0.0.1" --port=3306 --username="root" --password="wangxin@sl" --schema=scheduler --tables="user" -S "mysql-bin.000006" -L "700692"
在log目录下生产反向sql文件flashback_scheduler_20170221_154300.sql
#end_log_pos 701812 2017-02-21T15:26:27 1487661987 mysql-bin.000006;
update `user` set`username`=null,`cell_phone`=13930226699,`register_time`='2014-02-26 18:09:44',`school_code`=1,`email`=null,`usertype`=3,`state`=1,`password`='bc41014a6785b133a3c4fe29c1fc181e',`id`=1 where `id`=1;
update `user` set`username`=null,`cell_phone`=18818272661,`register_time`='2014-02-26 23:08:14',`school_code`=1,`email`=null,`usertype`=3,`state`=1,`password`='2b7dc70e9ef4aec3b36d9ed01f6c3917',`id`=664 where `id`=664;
update `user` set`username`=null,`cell_phone`=15821823213,`register_time`='2014-02-26 23:08:15',`school_code`=1,`email`=null,`usertype`=3,`state`=1,`password`='19c0f7f7008765f55cfd64af4b7b7009',`id`=666 where `id`=666;
update `user` set`username`=null,`cell_phone`=18817817795,`register_time`='2014-02-26 23:08:17',`school_code`=1,`email`=null,`usertype`=3,`state`=1,`password`='86b28ea44b6e4bc0b7d5c5010d288f1c',`id`=670 where `id`=670;
update `user` set`username`=null,`cell_phone`=13482311832,`register_time`='2014-02-26 23:08:26',`school_code`=1,`email`=null,`usertype`=1,`state`=1,`password`='db79ffb99fafbf059d525c93e7c1e38c',`id`=681 where `id`=681;
update `user` set`username`=null,`cell_phone`=15026616052,`register_time`='2014-02-26 23:08:28',`school_code`=1,`email`=null,`usertype`=1,`state`=1,`password`='aa237deac77a9b5c652e14b888aefccf',`id`=682 where `id`=682;
update `user` set`username`=null,`cell_phone`=15121110056,`register_time`='2014-02-26 23:08:29',`school_code`=1,`email`=null,`usertype`=1,`state`=1,`password`='dae5acb6bd5de68011dd55f1b4d31303',`id`=685 where `id`=685;
将数据导入mysql恢复
mysql -uroot -p scheduler
最后验证下数据,释放全局表锁
心得:这个回滚工具在误操作急救的时候比较好用,相对于使用全备加binlog恢复的方式更加便捷有效