zoukankan      html  css  js  c++  java
  • MySQL的闪回策略

    闪回原理

      既然binlogevent形式记录了所有的变更信息,那么我们把需要回滚的event,从后往前回滚回去即可。

      对于单个event的回滚,我们以表test.user来演示原理

      mysql> show create table test.user G

      ******************1. row************************

      Table: user

      Create Table: CREATE TABLI ‘user’ (‘id’ int(11) NOT NULL AUTO_INCREMENT,’name’ varchar(10) DEFAULT NULl PRIMARY KEY (‘id’) ENGINE=InnoDB AUTO INCREMENT=6 DEFAULT CHARSET=utf8

    对于delete操作,我们从binlog提取出delete信息,反向生成的回滚语句是Insert(:为了方便解释,我们用 binlog2sql将原始 binlog转化成了可读SQL)

      原始:DELETE FROM test, user where id=1 AND ‘name’=’小赵’;

      回滚:INSERT INTO test.user(id,name) VALUES(1,"小赵");

    对于insert操作,反向生成delete回滚语句。

      原始:INSERT INTo test.user(‘id’,’name’) values (2,’小钱’);

      回滚:DELETE from test.user where id=2, name=’小钱’;

    对于update操作,回滚sql应该交换SETWHEREI的值,反向生成update语句;

      原始UPDATE test.user SET id=3,name=’小李where id=3 AND name=’小孙’;

      回滚UPDATE test.user SET id=3,name=’小孙’’ where id=3 AND name=’小李’;

    闪回实战

      真实的闪回场景中,最关键的是能快速筛选出真正需要回滚的SQL

      我们使用开源工具binlog2sql来进行实战演练。binlog2sql由美团点评DBA团队(上海)出品,多次在线上环境做快速回滚。

      首先我们安装binlog2sql

        # git clone https://github.co/danfengcao/binlog2sql.git&&cdbinlos

        # pip install -r requirements.txt

      背景:小明在11:44时误删了testuser表大批的数据,需要紧急回滚。

      testuser表原有数据

         mysql> select * from user;

        +-----+------+--------------------------+

        | id | name| addtime     |

        +-----+------+--------------------------+

        |1  |小赵|2013-11-11 00:04:33|

        |2  |小钱|2014-11-11 00:04:48|

        |3  |小孙|2016-11-11 20:25:00 |

        |4  |小李|2013-11-11 09:00:00|

        ·······

        +-----+------+--------------------------+

          16384 rows in set (0. 04 sec)

      11:44,user表大批数据被误刪除。与此同时,正常业务数据是在继续写入的

         mysql> delete from user where addtime>'2014-01-01

         Query OK, 16128 rows affected (0. 18 sec)

         mysql> seLect count(*) from user;

         +-------------+

         | count(*) |

         +-------------+

         | 261    |

         +-------------+

    恢复数据步骤:

    1. 登录mysql,查看目前的binlog文件

         mysql> seLect count(*) from user;

        +-------------------------+--------------+

        | Log_name      | File_size  |

        +-------------------------+--------------+

        | mysql-bin.000053 |168652863|

        | mysql-bin.000054 | 504549   |

         +-------------------------+---------------+

    1. 最新的binlog文件是mysql-bin.000054。我们的目标是筛选出需要回滚的SQL,由于误操作人只知道大致的误操作时间,我们首先根据时间做一次过滤。只需要解析testuser表。(注:如果有多个sql误操作,则生成的binlog可能分布在多个文件,需解析多个文件)

    # python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -padmin

    raw.sql输出:

    delete from test.user where ‘addtime’=’2014-11-11 00:45:15’ and id=456 and name=’照照’;

    delete from test.user where ‘addtime’=’2014-11-12 00:45:15’ and id=486 and name=’溜溜’;

    ······

    delete from test.user where ‘addtime’=’2014-11-18 00:45:15’ and id=496 and name=’海海’;

    insert into ‘test’.’user’(‘addtime’,’id’,’name’) values (2012-12-14 00.45.15,459,’可可’)

    1. 根据位置信息,我们确定了误操作sql来自同一个事务,准确位置在257427-504272之间(binlog2sql对于同一个事务会输出同样的start position)。再根据位置过滤,使用 -B 选项生成回滚sql,检查回滚sql是否正确。(注:真实场景下,生成的回滚SQL经常会需要进一步筛选。结合grep、编辑器等)

    # python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -padmin

    rollbach.sql输出:

    insert into ‘test’.’user’(‘addtime’,’id’,’name’) values (2016-12-14 00.45.15,456,’照照’)

    insert into ‘test’.’user’(‘addtime’,’id’,’name’) values (2016-12-15 00.45.15,486,’溜溜’)

    ······

    insert into ‘test’.’user’(‘addtime’,’id’,’name’) values (2016-12-16 00.45.15,459,’可可’)

    # wc -l /tmp/rollback.sql

    16128  /tmp/rollback.sql

    1. 与业务方确认回滚sql没问题,执行回滚语句。登录mysql,确认回滚成功。

    # mysql -h127.0.0.1 -P3306 -uadmin -padmin < /tmp/rollback.sql

    mysql> select count(*) from user;

    +----------------+

    | count(*)   |

    +----------------+

    | 16389    |

    +----------------+

    TIPS

    闪回的关键是快速筛选出真正需要回滚的SQL

    先根据库、表、时间做一次过滤,再根据位置做更准确的过滤。

    由于数据一直在写入,要确保回滚sql中不包含其他数据。可根据是否是同一事务、误操作行数、字段值的特征等等来帮助判断。

    执行回滚sql时如有报错,需要查实具体原因,一般是因为对应的数据已发生变化。由于是严格的行模式,只要有唯一键(包括主键)存在,就只会报某条数据不存在的错,不必担心会更新不该操作的数据。

    如果待回滚的表与其他表有关联,要与开发说明回滚和不回滚各自的副作用,再确定方案。

    回滚后数据变化,可能对用户和线上应用造成困惑(类似幻读)

    再重复下最重要的两点:筛选出正确SQL!沟通清楚!

    闪回工具

      MySQL闪回特性最早由阿里彭立勋开发,彭在2012年给官方提交了一个patch,并对闪回设计思路做了说明。彭之后,又有多位人员针对不同mysql版本不同语言开发了闪回工具,原理用的都是彭的思路。

    闪回工具按实现方式分成了三类。

    第一类是以patch形式集成到官方工具mysqlbinlog中。以彭提交的patch为代表。

    缺点

    1. 兼容性差、项目活跃度不高。由于binlog格式的变动,如果闪回工具作者不及时对补丁升级,则闪回工具将无法使用。目前已有多位人员分别针对mysql5.55.65.7开发了patch,部分项目代码公开,但总体上活跃度都不高。
    2. 难以添加新功能,实战效果欠佳。在实战中,经常会遇到现有patch不满足需求的情况,比如要加个表过滤,很简单的一个需求,代码改动也不会大,但对大部分DBA来说,改mysql源码还是很困难的事。
    3. 安装稍显麻烦。需要对mysql源码打补丁再编译生成。

    优点

    1. 上手成本低。mysqlbinlog原有的选项都能直接利用,只是多加了一个闪回选项。闪回特性未来有可能被官方收录。
    2. 支持离线解析。

    第二类是独立工具,通过伪装成slave拉取binlog来进行处理。以binlog2sql为代表。

     

    缺点

    必须开启MySQL server

    优点

    1. 兼容性好。伪装成slavebinlog这项技术在业界应用的非常广泛,多个开发语言都有这样的活跃项目,MySQL版本的兼容性由这些项目搞定,闪回工具的兼容问题不再突出。
    2. 添加新功能的难度小。更容易被改造成DBA自己喜欢的形式。更适合实战。
    3. 安装和使用简单。

    第三类是简单脚本。先用mysqlbinlog解析出文本格式的binlog,再根据回滚原理用正则进行匹配并替换。

    缺点

    1. 通用性不好。
    2. 可靠性不好。

    优点

    1. 脚本写起来方便,往往能快速搞定某个特定问题。
    2. 安装和使用简单。
    3. 支持离线解析。

    就目前的闪回工具而言,线上环境的闪回,笔者建议使用binlog2sql,离线解析使用mysqlbinlog

    MySQL闪回工具之binlog2sql

    用途:

    数据回滚;;主从切换后数据不一致的修复;;从binlog生成标准SQL,带来的衍生功能;;

    使用python-mysql-replication作为实时解析MySQL binlog来获取各个event

    python-mysql-replication实现了MySQL复制协议,客户端伪装成slave来获取主的binlogevent,使用它可以通过读取binlog来实现一些完成实时计算,而无须先存储再计算。但这也是一个缺点,如果没有前提,binlog2sql就无法完成工作,而且如果在高并发的环境中要进行解析binlog,也就相当于多了一个同步线程在主上读取数据,加大了主的负担。

    在生产使用之前,一定在测试通过之后使用,确保没有数据错误。

    关于DDLflashback

      这里所述的flashback仅针对DML语句的快速回滚。但如果误操作是DDL的话,是无法利用binlog做快速回滚的,因为即使在row模式下,binlog对于DDL操作也不会记录每行数据的变化。要实现DDL快速回滚,必须修改MySQL源码,使得在执行DDL前先备份老数据。

      在flashback模式下,一次性处理的binlog不易过大,不能超过内存大小。

      目前有多个mysql定制版本实现了DDL闪回特性,阿里林晓斌团队提交了patch(修改mysql server的源码MySQL官方,MariaDB预计在不久后加入包含DDLflashback特性。DDL闪回的副作用是会增加额外存储而且低频。

  • 相关阅读:
    Chrome cookies folder
    Fat URLs Client Identification
    User Login Client Identification
    Client IP Address Client Identification
    HTTP Headers Client Identification
    The Personal Touch Client Identification 个性化接触 客户识别
    购物车 cookie session
    购物车删除商品,总价变化 innerHTML = ''并没有删除节点,内容仍存在
    453
    购物车-删除单行商品-HTMLTableElement.deleteRow()
  • 原文地址:https://www.cnblogs.com/5945yang/p/11694691.html
Copyright © 2011-2022 走看看