本文转载自微信公众号「Python技术」,妈妈作者派森酱。再也转载本文请联系Python技术公众号。不用把数 数据是担心丢现代大小厂的重要资产,保护和恢复数据成为了重要的据弄技能, 最近几年,妈妈常有一些无良程序员删库跑路的再也情况,不仅给所在企业更是不用把数给自己造成重大的损失。 另外,担心丢即使不是据弄故意的情况下,也会因为疏忽造成数据误操作,妈妈是再也一件及麻烦又头疼的事情…… 最近的一个项目里,客户数据因为维护不当,不用把数导致数据丢失,担心丢为了挽回数据,据弄并建立一个跨网闸(内部组网之间不通,无法使用 MySql 主从同步)的数据备份机制,发现了一个神器 binlog2sql[1]。 研究了一番之后,不仅恢复了误操作丢失的数据,还通过 binlog2sql 将主服务器上的源码库 binlog[2] 转化为 SQL 语句,存入文件,实现了数据同步! binlog2sql 使用 Python 开发,所以需要 Python 环境,可参考 Python 环境搭建 将 binlog2sql 用 git 克隆的本地,GitHub 上的地址是: https://github.com/danfengcao/binlog2sql.git 通过 binlog2sql 目标下的 requirements.txt 安装依赖包 提示:推荐在 Python 虚拟环境中安装,创建虚拟环境可参考 Python 虚拟环境 看这一篇就够了 一切顺利的话,很快就可完成安装。 命令行进入 binlog2sql 代码目录下测试一下 由于没加任何参数,所以打印出使用说明,那说明安装正常了。 binlog2sql 是通过分析 MySql 数据库的 binlog 文件,从中解析出需要执行的 sql 语句的。 那么使用时需要提供一些必要的参数,其中重要的有数据库服务器链接信息,需要分析的 binlog 文件名等, 还可以指定解析的起始和结束位置,以及开始和结束时间。 是骡子是香港云服务器马拉出来溜溜。 假如库表 tb_user 中的数据如下: 这时不小心执行了一个删操作,将数据误删了 如何恢复呢? 我们看一下数据库的日志情况 会看到类似这样的结果 注意:只有 MySql 数据库打开了日志记录功能,才能查询到,打开日志功能请参考 binlog日志开启和使用[3] 可以看出,目前日志记录在文件 mysql-bin.000002 中,当前最新的记录位置是 12546 行 假如当时误操作的时间是上午 11点半左右(可能着急吃饭,没注意),那么预估一个时间范围,比如 11点25 到 11点35,看看一下当时的操作: 输出为: 可以看出,第二行开始到第五行为删除语句,查看语句最后的起始和结束位置 start 12728 end 12829 即 binlog 中,删除执行的位置在 12728-12829 之间,于是锁定精确位置,生成回滚语句: 注意参数 -B,意思是生成回滚 SQL,即生成的是撤销之前操作的语句 输出为: 从输出的服务器租用语句来看,顺序是删除的倒序,而且已经将原来的 delete 语句改为了 insert 语句,也就是原来操作的逆操作 如果确认语句没问题,执行生成的语句就可以了 是不是既方便又高效呢? binlog2sql 功能强大,使用起来也很方便,看看其他功能吧。 作为一个命令行工具,功能都体现在参数里,可分为 解析模式、解析目标、解析范围三部分。 binlog2sql 支持两个解析模式,默认的是单次解析,即运行一次解析一次, 还可以支持持续解析,即不间断地从目标数据库地 binlog 中解析出 sql 来,持续解析通过参数 --never-stop 开启, 开启之后,线程不会退出,一直处于运行状态,会自动判断 binlog 的变化,对变化部分增量式解析。 这种模式可以用于数据库同步,不过生产上使用前,最好考虑各种异常情况,比如重启,网络中断等情况。 参数 -K 或 --no-primany-key 表示的去除 INSERT 语句中的主键,这个在数据汇总的场景下很方便,可以避免多个数据源中主键冲突的问题。 参数 -B 或 --flashback,表示回滚模式,在上面的例子中展示过,即会解析成逆操作的 sql 语句。 在回滚模式下,每生成一千条 SQL 语句会加一个 SLEEP 语句,是为以免数据执行时产生拥堵,默认为 1 秒,可以通过 --back-interval 参数来设置, 例如 --back-interval 2 表示暂停 2 秒。 MySql 设置 binlog 时可以指定记录哪个库,以及哪些表,即目标。 那么用 binlog2sql 也可以指定解析目标。 参数 -d 或 --databases 用于指定数据库,如果多个库,用空格分隔,例如 -d db1 db2; 参数 -t 或 --tables 用于指定库表,多个库表用空格分隔,例如 -t tb1 tb2。 如果指定解析目标不仅效率更高,而且分析和执行解析的结果也更方便。 范围包括 binlog 文件范围,时间范围 以及 行范围,例如前面例子中用到了 时间范围 和 行范围。 文件范围 用 --start-file 和 --stop-file 参数来指定,只需要提供 binlog 文件名即可,不需要写全路径,这是因为,binlog2sql 会自动根据目标服务器配置读取 binlog 文件; 时间范围 用 --start-datetime 和 --stop-datetime 参数来指定,时间格式为 %Y-%m-%d %H:%M:%S; 行范围 用 --start-position 和 --stop-position 参数来指定,也可以简写为 --start-pos 和 --end-pos。 binlog2sql 不仅是一个实用的工具,而且也是个研究和学习的好例子。 只有不到 500 行代码,很容易阅读; 阅读源码,不仅能深入了解其实现原理,而且还可以学习到很多好用法。 binlog2sql 的原理是,利用 pymysql 从目标服务器上获取 binlog 信息,然后锁定范围,使用 pymysqlreplication 解析 binlog 文件,最后,得到需要解析出的 sql 语句。 在这基础上,做了一些功能性扩展,比如解析范围,解析模式等,相对来说比较简单,很容易看懂。 编程时处理命令行参数是机械而繁琐的,特别是有不同性质的性质和别名的参数 binlog2sql 中利用了 argparse 模块[4], argparse 模块可以让人轻松编写用户友好的命令行接口。程序定义它需要的参数,argparse 可以从 sys.argv 解析出提供的命令行参数。而且 argparse 模块还会自动生成帮助和使用手册,并在用户给程序传入无效参数时报出错误信息。 很容易就能编程高大上的命令行程序接口,再也不用为很 low 的程序接口发愁了。 binlog2sql 在回滚模式(即提供了参数 -B)中,使用了一个临时文件记录解析出来的 SQL 语句,并且在完成之后删除。 一般来说,在完成后主动删除文件即可,不过如果能利用 with 块的资源回收功能就更好了。 查看源码,会看到一个创建文件写法: @contextmanager[5] 指示器可以将一个生成器[6],作为一个上下文管理器[7], 那么: with 声明部分,会执行前会执行 yield 语句之前的部分 with 范围内,会执行 yield 语句,即返回一个需要后续处理的对象,比如文件,后续处理是关闭 with 执行完成前,会执行 yield 语句之后的代码 那么这段代码的意义就是,当文件使用完成后,关闭文件,并且删除掉。 使用方式为: 这样无论如何只要 with 块执行完,文件就会被删除,不用担心忘记,是不是很优雅? 除了这两点,还有很多值得把玩的地方,有兴趣的话可以读读源码。 无论是什么工具,都需要有一定的基础和良好的习惯上才会发挥作用,比如得开启 MySql 的 binlog 日志,并由记录工作的习惯。 同时,任何工具方法都有它的特点,可以在了解功能的同时,研究一下其使用原理,是一个很好的技能提升机会。 很多人在抱怨,没有应用场景,没有实际项目,其实研究这些工具,就会有事半功倍的效果。 比心 参考资料 [1]binlog2sql: https://github.com/danfengcao/binlog2sql [2]binlog: https://laijianfeng.org/2019/03/MySQL-Binlog-%E4%BB%8B%E7%BB%8D/ [3]binlog日志开启和使用: https://juejin.cn/post/6854573218485944333 [4]argparse 模块: https://docs.python.org/zh-cn/3/library/argparse.html [5]@contextmanager: https://www.liaoxuefeng.com/wiki/1016959663602400/1115615597164000 [6]生成器: https://www.programiz.com/python-programming/generator [7]上下文管理器: https://www.geeksforgeeks.org/context-manager-in-python/神器出场
安装
简介
身手不凡
恢复被删数据
解析 SQL
解析模式
解析目标
解析范围
深入了解
实现原理
命令行参数
文件处理上下文(context)
总结