暂无图片
暂无图片
4
暂无图片
暂无图片
4
暂无图片

聊聊 Mysql 的 Flashback

原创 大表哥 2022-04-12
3687

image.png
大家好,大表哥这次带来的是mysql的flashback.

相信用过ORACLE的小伙伴都知道, flashback 闪回这个功能很强大。 具体的可以分为 database 级别的闪回和表 级别的闪回。

database 级别的闪回依赖的是 oracle FRA 中保存的 flashback 的log 日志
table 级别的闪回依赖是 undo 表空间的中保存的数据。实际上是基于MVCC的 snapshot 的查询召回历史的数据。

Mysql 做为开源产品,原生是不支持闪回这个功能的。 但是开源社区是强大的,大众点评开源了一款基于mysql binlog为依赖的类似于flashback 的工具: binlog2sql. 这个在业界是十分知名的。

下面我们来看一下这个工具:
官网:https://github.com/danfengcao/binlog2sql (需要科学上网)

image.png

我们根据readme这个文件来下载和安装一下

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

下载完成后:

INFRA [mysql@wqdcsrv3352 binlog2sql]# ls binlog2sql-master.zip INFRA [mysql@wqdcsrv3352 binlog2sql]# unzip binlog2sql-master.zip Archive: binlog2sql-master.zip 5a8e65c432e74950b48b7ead28f424ec931b755d creating: binlog2sql-master/ inflating: binlog2sql-master/.gitignore inflating: binlog2sql-master/LICENSE inflating: binlog2sql-master/README.md creating: binlog2sql-master/binlog2sql/ inflating: binlog2sql-master/binlog2sql/__init__.py inflating: binlog2sql-master/binlog2sql/binlog2sql.py inflating: binlog2sql-master/binlog2sql/binlog2sql_util.py creating: binlog2sql-master/example/ inflating: binlog2sql-master/example/mysql-flashback-priciple-and-practice.md inflating: binlog2sql-master/requirements.txt creating: binlog2sql-master/tests/ inflating: binlog2sql-master/tests/test_binlog2sql_util.py
复制

我们根据 requirements.txt 安装一下依赖的类库:

INFRA [mysql@wqdcsrv3352 binlog2sql-master]# pip install -r requirements.txt Requirement already satisfied: PyMySQL==0.7.11 in /usr/lib/python2.7/site-packages (from -r requirements.txt (line 1)) Requirement already satisfied: wheel==0.29.0 in /usr/lib/python2.7/site-packages (from -r requirements.txt (line 2)) Requirement already satisfied: mysql-replication==0.13 in /usr/lib/python2.7/site-packages (from -r requirements.txt (line 3)) You are using pip version 9.0.1, however version 21.3.1 is available. You should consider upgrading via the 'pip install --upgrade pip' command.
复制

现在我们尝试一下; 把binlog文件中的语句 抽取出来:

我们先创建一张表:
操作的时间抽顺序是:

1)记录上时间是 2022-01-02 16:44:04
2)在testdb下创建表t2
3)向T2表插入一条记录 jason
4)再次向T2表中 插入记录 jason2

Current database: performance_schema +---------------------+ | now() | +---------------------+ | 2022-01-02 16:44:04 | +---------------------+ 1 row in set (0.18 sec) mysql> use testdb Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> create table t2 (id int not null primary key, name varchar(10)); Query OK, 0 rows affected (0.03 sec) mysql> insert into t2 values (1,'jason'); Query OK, 1 row affected (0.02 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> insert into t2 values (2,'jason2'); Query OK, 1 row affected (0.01 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec)
复制

那么现在我们想捕获到 binlog日志中的 从时间点 2022-01-02 16:44:04 开始的SQL 语句:

INFRA [root@wqdcsrv3352 binlog2sql]# python ./binlog2sql.py -h 127.0.0.1 -P3210 -ujason -padmin123 -dtestdb --start-file='mysql1231_binlog.000005' --start-datetime='2022-01-02 16:44:04' USE testdb; create table t2 (id int not null primary key, name varchar(10)); INSERT INTO `testdb`.`t2`(`id`, `name`) VALUES (1, 'jason'); #start 1762 end 1984 time 2022-01-02 16:45:27 INSERT INTO `testdb`.`t2`(`id`, `name`) VALUES (2, 'jason2'); #start 2093 end 2317 time 2022-01-02 17:06:34
复制

目前是可以得到相应的SQL语句的:指定参数 --flashback 即可
1)建表的DDL语句
2)还有2条插入的语句

我们还可以测试生成一下flashback的语句:

INFRA [root@wqdcsrv3352 binlog2sql]# python ./binlog2sql.py -h 127.0.0.1 -P3210 -ujason -padmin123 -dtestdb --start-file='mysql1231_binlog.000005' --start-datetime='2022-01-02 16:44:04' --flashback DELETE FROM `testdb`.`t2` WHERE `id`=2 AND `name`='jason2' LIMIT 1; #start 2093 end 2317 time 2022-01-02 17:06:34 DELETE FROM `testdb`.`t2` WHERE `id`=1 AND `name`='jason' LIMIT 1; #start 1762 end 1984 time 2022-01-02 16:45:27
复制

此时,工具已经为我们生成了2条 delete语句,并且是之前的倒序输出。

接下来我们更近一步, 对于熟悉python 编程的小伙伴来说, 下面我们可以看看 binlog2sql 的源代码是如何实现binlog的读取的:

我们用pycharm 把项目源代码打开:

image.png

image.png

我们来观察一下项目的目录:

image.png

目录来时是十分清晰的:
–binlog2sql 包是程序的只要目录:只要的文件是binlog2sql这个文件
–example 包是介绍 readme类似的
–tests 包是 mock 测试的程序

从项目的依赖的类库是比较少的:requirements.txt

PyMySQL==0.7.11 wheel==0.29.0 mysql-replication==0.13
复制

这里需要重点介绍一下这个mysql-replication 类库, 这个类库是核心解析mysql binlog的功能的类库。

这个类库是做mysql binlog的复制同步用的, 功能是解析mysql的binlog 之后,同步给下游数据库的mysql,甚至是异构的NOSQL数据库像是Mongo, ES, 消息队列kafka 什么的

我们可以参考一下 mysql-replication 类库的官网,里面有详细的介绍: https://python-mysql-replication.readthedocs.io/en/latest/

image.png

官方介绍这个类库的场景如下:

MySQL to NoSQL database replication – mysql 到 nosql 的数据库之间的复制
MySQL to search engine replication – mysql ETL到查询引擎
Invalidate cache when something change in database – ??? 这个暂时不太懂
Audit – 审计功能
Real time analytics --实时分析的功能

关于解析binlog的类库的一些限制:

1)binlog_row_image=full 日志的image必须是full
2)一些类型不支持:GEOMETRY和BOOLEAN,BOOL

核心的类: BinLogStreamReader 来读取Event: 其中Row events 只要包括: WriteRowsEvent,UpdateRowsEvent,DeleteRowsEvent, 也就是我们常用的insert,update,delete 语句。

下面我们跑一个测试程序来实时读取mysql binlog的event 来体验一下:

我们需要创建一下账户和授权:

mysql> create user binlog_reader@'%' identified with mysql_native_password by "admin123_abdD"; Query OK, 0 rows affected (0.00 sec) mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT, SELECT ON *.* TO binlog_reader@'%'; Query OK, 0 rows affected (0.00 sec)
复制

我们来运行一下这段测试的代码:

from pymysqlreplication import BinLogStreamReader MYSQL_SETTINGS = { "host": "127.0.0.1", "port": 3306, "user": "root", "passwd": "" } def main(): # server_id is your slave identifier, it should be unique. # set blocking to True if you want to block and wait for the next event at # the end of the stream stream = BinLogStreamReader(connection_settings=MYSQL_SETTINGS, server_id=3, blocking=True) for binlogevent in stream: binlogevent.dump() stream.close() if __name__ == "__main__": main()
复制

从结果中我们可以看到我们之前创建账户和授权的语句都可以打印到控制台上:

image.png

我们在测试一下table DDL和DML的语句: mysql 终端中输入建表语句:

mysql> create table tab1 (id int not null, name varchar(20)); Query OK, 0 rows affected (0.00 sec) mysql> insert into tab1 values (1,'jason'); Query OK, 1 row affected (0.01 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec)
复制

观测python 程序的console输出:

=== QueryEvent ===
Date: 2022-04-12T14:15:00
Log position: 189051
Event size: 110
Read bytes: 110
Schema: b'test_db'
Execution time: 0
Query: create table tab1 (id int not null, name varchar(20))
=== WriteRowsEvent ===
Date: 2022-04-12T14:15:48
Log position: 189329
Event size: 23
Read bytes: 12
Table: test_db.tab1
Affected columns: 2
Changed rows: 1
Values:
--
* id : 1
* name : jason

复制

由此可见创建表的DDL属于Query Event, DML的insert 属于WriteRowsEvent, 以此类推 update和delete 属于UpdateRowsEvent,DeleteRowsEvent。

这3个DML Event 是mysql 的flashback的主要监听的event类型。

我们搞明白了mysql-replication 这个类库之后, 再次回到大众点评的 binlog2sql 这个flashback的工具:

核心类 binlog2sql的核心方法process_binlog 调用如下:

image.png

感兴趣的小伙伴,可以自行动手下载源代码调试一下,并结合自己工作中实际的需求进行自定义开发。

大表哥认为自己动手来实践才算是最大的乐趣! 动起手来吧!

最后修改时间:2022-04-12 15:40:15
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
1人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

暂无图片
3年前
评论
暂无图片 0
对应的资源 https://www.modb.pro/download/516931
3年前
暂无图片 点赞
评论
暂无图片
3年前
评论
暂无图片 0
使用PYTHON脚本语言的吗? 听说贼难安装 大家可以使用GO语言开发的my2sql
3年前
暂无图片 点赞
1
大表哥
暂无图片
3年前
回复
暂无图片 0
是的 这个是 python 开发的 还有个c语言版的 叫 myflash
3年前
暂无图片 点赞
回复
墨天轮福利君
暂无图片
3年前
评论
暂无图片 0
您好,您的文章已入选墨力原创作者计划合格奖,10墨值奖励已经到账请查收! ❤️我们还会实时派发您的流量收益。
3年前
暂无图片 点赞
评论