zoukankan      html  css  js  c++  java
  • mysql闪回工具--binlog2sql实践

       DBA或开发人员,有时会误删或者误更新数据,如果是线上环境并且影响较大,就需要能快速回滚。传统恢复方法是利用备份重搭实例,再应用去除错误sql后的binlog来恢复数据。此法费时费力,甚至需要停机维护,并不适合快速回滚。也有团队利用LVM快照来缩短恢复时间,但快照的缺点是会影响mysql的性能。现在有不少好用而且效率又高的开源闪回工具如binlog2sql、mysqlbinlog_flashback,这些工具在工作中给DBA减轻了不少痛苦,以下针对binlog2sql的使用进行实践演练。

    binlog2sql的用途:

    • 数据快速回滚(闪回)
    • 主从切换后数据不一致的修复
    • 从binlog生成标准SQL,带来的衍生功能

    安装binlog2sql前先安装git和pip:

    yum -y install epel-release 
    yum -y install git  python-pip

    安装binlog2sql:

    git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
    pip install -r requirements.txt

     MySQL的配置要开启以下选项:

    [mysqld]
    server_id = 1
    log_bin = /var/log/mysql/mysql-bin.log
    max_binlog_size = 1G
    binlog_format = row
    binlog_row_image = full

    要授权一个用户有以下权限:

    SELECT, REPLICATION SLAVE, REPLICATION CLIENT

    权限说明:

    • select:需要读取server端information_schema.COLUMNS表,获取表结构的元信息,拼接成可视化的sql语句
    • super/replication client:两个权限都可以,需要执行'SHOW MASTER STATUS', 获取server端的binlog列表
    • replication slave:通过BINLOG_DUMP协议获取binlog内容的权限

    binlog2sql的使用参数说明:

    mysql连接配置

    -h host; -P port; -u user; -p password

    解析模式

    --stop-never 持续同步binlog。可选。不加则同步至执行命令时最新的binlog位置。

    -K, --no-primary-key 对INSERT语句去除主键。可选。

    -B, --flashback 生成回滚语句,可解析大文件,不受内存限制,每打印一千行加一句SLEEP SELECT(1)。可选。与stop-never或no-primary-key不能同时添加。

    解析范围控制

    --start-file 起始解析文件。必须。

    --start-position/--start-pos start-file的起始解析位置。可选。默认为start-file的起始位置。

    --stop-file/--end-file 末尾解析文件。可选。默认为start-file同一个文件。若解析模式为stop-never,此选项失效。

    --stop-position/--end-pos stop-file的末尾解析位置。可选。默认为stop-file的最末位置;若解析模式为stop-never,此选项失效。

    --start-datetime 从哪个时间点的binlog开始解析,格式必须为datetime,如'2016-11-11 11:11:11'。可选。默认不过滤。

    --stop-datetime 到哪个时间点的binlog停止解析,格式必须为datetime,如'2016-11-11 11:11:11'。可选。默认不过滤。

    对象过滤

    -d, --databases 只输出目标db的sql。可选。默认为空。

    -t, --tables 只输出目标tables的sql。可选。默认为空。

    进行用户授权操作(这里只是举例子):

    mysql> GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO  'flashuser'@'127.0.0.1' identified by 'flash123';
    Query OK, 0 rows affected (0.00 sec)

     我们可以看看现在有的数据:

    复制代码
    mysql>  show global variables like 'binlog_format';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | binlog_format | ROW   |
    +---------------+-------+
    1 row in set (0.00 sec)
    
    mysql>

    mysql> show master status;
    +---------------------+----------+--------------+------------------+-------------------------------------------+
    | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +---------------------+----------+--------------+------------------+-------------------------------------------+
    | mysql-binlog.000003 | 17724 | | | 8eacaa05-ef11-11e9-89cd-5254007d488a:1-56 |
    +---------------------+----------+--------------+------------------+-------------------------------------------+
    1 row in set (0.00 sec)

    mysql> select * from tb1;

    mysql> select * from stu;
    +----+----------+
    | id | name |
    +----+----------+
    | 0 | lisi |
    | 1 | lili |
    | 2 | zhangsan |
    +----+----------+
    3 rows in set (0.00 sec)

    mysql>
    复制代码

    我们现在进行数据的DML操作:

    复制代码

    mysql> insert into stu values(3, 'wangwu');
    Query OK, 1 row affected (0.04 sec)

    mysql> insert into stu values(4, 'zhaoliu');
    Query OK, 1 row affected (0.03 sec)

    mysql> insert into stu values(5, 'xiexun');
    Query OK, 1 row affected (0.12 sec)

    mysql> insert into stu values(6, 'beifang');
    Query OK, 1 row affected (0.03 sec)

    mysql> select * from stu;
    +----+----------+
    | id | name |
    +----+----------+
    | 0 | lisi |
    | 1 | lili |
    | 2 | zhangsan |
    | 3 | wangwu |
    | 4 | zhaoliu |
    | 5 | xiexun |
    | 6 | beifang |
    +----+----------+
    7 rows in set (0.00 sec)

    mysql>
    复制代码

    下面我们使用binlog2sql进行格式为ROW的binlog生成标准SQL,带个-d的参数指定库名:

    复制代码
     
    [root@master ~]# python /tmp/binlog2sql/binlog2sql/binlog2sql.py -uglon -h192.168.7.141 -pglon123456 -dtest01 --start-file='mysql-binlog.000003' > test01.sql

    [root@master ~]# cat test01.sql

    USE test01;
    INSERT INTO `test01`.`stu`(`id`, `name`) VALUES (3, 'wangwu'); #start 7253 end 7484 time 2019-10-16 09:46:14
    INSERT INTO `test01`.`stu`(`id`, `name`) VALUES (4, 'zhaoliu'); #start 7580 end 7813 time 2019-10-16 09:46:28
    INSERT INTO `test01`.`stu`(`id`, `name`) VALUES (5, 'xiexun'); #start 7909 end 8140 time 2019-10-16 09:46:41
    INSERT INTO `test01`.`stu`(`id`, `name`) VALUES (6, 'beifang'); #start 8236 end 8469 time 2019-10-16 09:46:52
    [root@master ~]#

    复制代码

    我们可以看到,刚刚执行过的sql都生成出来了。

    我们现在对test01这个库的所有操作生成反向SQL,这个时候需要在上面语句的基础上带一个-B参数,就是flashback闪回的意思:

    复制代码
    [root@db_server_xuanzhi ~]#python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi --start-file='mysql-bin.000107' -B  > rollback_xuanzhi.sql

    [root@master ~]# python /tmp/binlog2sql/binlog2sql/binlog2sql.py -uglon -h192.168.7.141 -pglon123456 -dtest01 --start-file='mysql-binlog.000003' -B > rollback_test01.sql
    [root@master ~]# cat rollback_test01.sql
    DELETE FROM `test01`.`stu` WHERE `id`=6 AND `name`='beifang' LIMIT 1; #start 8236 end 8469 time 2019-10-16 09:46:52
    DELETE FROM `test01`.`stu` WHERE `id`=5 AND `name`='xiexun' LIMIT 1; #start 7909 end 8140 time 2019-10-16 09:46:41
    DELETE FROM `test01`.`stu` WHERE `id`=4 AND `name`='zhaoliu' LIMIT 1; #start 7580 end 7813 time 2019-10-16 09:46:28
    DELETE FROM `test01`.`stu` WHERE `id`=3 AND `name`='wangwu' LIMIT 1; #start 7253 end 7484 time 2019-10-16 09:46:14

    [root@master ~]#

    复制代码

    可以看到生成了跟上面标准SQL相反的SQL了,通过这些反向SQL可以进行误操的数据恢复。

    下面我们模拟对线上数据进行误操及恢复的过程:

    模拟一:误操把一个表的某些重要记录删除了,进行恢复

    我们把tb1的id>=3的数据删除:

    复制代码
    mysql> select * from tb1;
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    |  3 | cc   |
    |  4 | dd   |
    +----+------+
    4 rows in set (0.00 sec)
    
    mysql> delete from tb1 where id >= 3;
    Query OK, 2 rows affected (0.00 sec)
    
    mysql> select * from tb1;            
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    +----+------+
    2 rows in set (0.00 sec)
    
    mysql> show master status;
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000109 |      329 |              |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    复制代码

    现在通过binlog2sql进行生成反向SQL,binlog2sql可以指定生成那个库的那个表的标准SQL或者反向SQL,带一个-t的选择:

    [root@db_server_xuanzhi ~]# python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi -ttb1 --start-file='mysql-bin.000109' -B  > rollback_tb1.sql 
    [root@db_server_xuanzhi ~]# cat rollback_tb1.sql 
    INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 4 end 298 time 2017-03-23 12:39:20
    INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (3, 'cc'); #start 4 end 298 time 2017-03-23 12:39:20

    我们可以看刚刚对tb1进行误删的操作,都生成了反向的SQL语句也就是INSERT INTO,我们进行导入操作,看数据能否正常恢复

    [root@db_server_xuanzhi ~]#mysql -uroot -p123456 <./rollback_tb1.sql 
    Warning: Using a password on the command line interface can be insecure.
    [root@db_server_xuanzhi ~]#

    登录查看一下数据:

    复制代码
    mysql> select * from tb1;
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    |  3 | cc   |
    |  4 | dd   |
    +----+------+
    4 rows in set (0.00 sec)
    
    mysql> 
    复制代码

    可以看到数据可以正常的恢复。

    模拟二:误操作把一个表的数据删除了,经常出现的就是delete没带where条件

    复制代码
    mysql> select * from tb1;
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    |  3 | cc   |
    |  4 | dd   |
    +----+------+
    4 rows in set (0.00 sec)
    
    mysql> delete from tb1;
    Query OK, 4 rows affected (0.00 sec)
    
    mysql> select * from tb1;
    Empty set (0.00 sec)
    
    mysql> show master status;           
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000110 |      345 |              |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    我们用bin2log对这个表进行恢复:

    复制代码
    [root@db_server_xuanzhi ~]# python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi -ttb1 --start-file='mysql-bin.000110' -B  > rollback_tb1.sql  
    [root@db_server_xuanzhi ~]# cat rollback_tb1.sql 
    INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 4 end 314 time 2017-03-23 13:37:29
    INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (3, 'cc'); #start 4 end 314 time 2017-03-23 13:37:29
    INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (2, 'bb'); #start 4 end 314 time 2017-03-23 13:37:29
    INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (1, 'aa'); #start 4 end 314 time 2017-03-23 13:37:29
    [root@db_server_xuanzhi ~]# mysql -uroot -p123456 <./rollback_tb1.sql                                                                   
    Warning: Using a password on the command line interface can be insecure.
    
    
    复制代码

    再查询一下,数据是否把数据恢复了:

    复制代码
    mysql> select * from tb1;
    Empty set (0.00 sec)
    
    <Slave_1>[xuanzhi]> show master status;           
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000110 |      345 |              |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    1 row in set (0.00 sec)
    
    mysql> select * from tb1; 
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    |  3 | cc   |
    |  4 | dd   |
    +----+------+
    4 rows in set (0.00 sec)
    
    mysql> 
    复制代码

    可以看到可以正常恢复,但值得注意的是drop table 和truncate table 是无法生成反向SQL的,所以建议线上程序账号只给insert,upfate,select,delete权限。

    参考文章:

    https://www.cnblogs.com/xuanzhi201111/p/6602489.html

    https://github.com/danfengcao/binlog2sql

    https://github.com/danfengcao/binlog2sql/blob/master/example/mysql-flashback-priciple-and-practice.md

    总结:一、线上要对程序做好最小化权限控制,这样可以减少很多不必要的麻烦。

            二、现在开源比较好用的数据闪回工具有mysqlbinlog_flashbackbinlog2sql,给DBA日常维护带来了许多帮助。

  • 相关阅读:
    [Functional Programming] liftA2 and converge
    [Javascript] Convert a forEach method to generator
    [React Native] Up & Running with React Native & TypeScript
    [React] Create a Query Parameter Modal Route with React Router
    [ES2019] Represent Collision-free String Constants as Symbols in JavaScript
    形形色色的软件生命周期模型(4)——MSF、实用型
    整型数组处理算法(九)给定任意一个正整数,求比这个数大且最小的“不重复数”(性能优化)[2014百度笔试题]
    Easyui获取数据库date数据的显示
    [置顶] 如何更改CSDN博客高亮代码皮肤的样式,使博客看起来更有范(推荐)
    try-catch-finally 引发的奇怪问题
  • 原文地址:https://www.cnblogs.com/pyng/p/11683972.html
Copyright © 2011-2022 走看看