MyFlash
由于运维、DBA的误操作或是业务bug,咱们在操作中时不时会产生误删除数据状况。早期要想复原数据,只能让业务人员依据线上操作日志,结构误删除的数据,或许DBA经常使用binlog和备份的方式复原数据,不论那种,都十分费时费劲,而且容易出错。直到彭立勋***在MySQL社区为mysqlbinlog裁减了闪回性能。
在美团点评,咱们也遇到过研发人员误删主站的性能信息,从而造成主站长达2个小时无法用的状况。DBA同窗过后经常使用了技术团队自研的binlog2sql成功了数据复原,并屡次援救了线上误删数据造成的严重缺点。不过,binlog2sql在复原速度上不尽善尽美,因此咱们开发了一个新的工具——MyFlash,它很好地处置了上述痛点,能够繁难并且高效地启动数据复原。
如今该工具正式开源,开源地址为:。
闪回工具现状
先来看下目前市面上已有的恢停工具,咱们从成功角度把它们划分红如下几类。
mysqlbinlog工具配合sed、awk。该方式先将binlog解析成类SQL的文本,而后经常使用sed、awk把类SQL文本转换成真正的SQL。
给数据库源码打patch。该方式裁减了mysqlbinlog的性能,参与Flashback选项。
经常使用业界提供的解析binlog的库,而后启动SQL结构,其低劣代表是binlog2sql。
上述几种成功方式,重要是提供的过滤选项较少,比如不能提供基于SQL类型的过滤,须要回滚一个delete语句,造成在回滚时,须要联合awk、sed等工具启动挑选。
总结了上述几种工具的优缺陷,我以为现实的闪回工具须要有以下个性。
a. 无需把binlog解析成文本,再启动转换。
b. 提供原生的基于库、表、SQL类型、位置、期间等多种过滤方式。
c. 允许MySQL多个版本。
d. 关于数据库的代码重构不敏感,利于更新。
e. 自主掌控binlog解析,提供尽或许灵敏的方式。
在这些个性中,binlog的解析是一切上班的基础。接上去我会引见binlog的基本结构。
binlog格式初探
binlog格式概览
一个完整的binlog文件是由一个format description event扫尾,一个rotate event开头,两边由多个其余event组合而成。
binlog文件实例:
每个event都是由event header 和event>
表白的含意是:
170905 01:59:33 server id 10 end_log_pos 123 CRC32 0xed1ec563
Start: binlog v 4, server v 5.7.18-log created 170905 01:59:33
② table map event
表白的含意是:
170905 01:59:33 server id 10 end_log_pos 339 CRC32 0x3de40c0d
Table_map: `test`.`test4` mapped to number 238
③ update row event
表白的含意是:
170905 01:59:33 server id 10 end_log_pos 385 CRC32 0x179ef6dd
Update_rows: table id 238 flags: STMT_END_F
UPDATE `test`.`test4` WHERE @1=3 SET @1=13;
binlog event回滚
依据上方的binlog引见,可以看到每个binlog event中event header有个type_code,其中insert为30,update为31,delete为32。关于insert和delete两个雷同的操作,只要把type_code调换,则在binlog event级别成功回滚。
而关于update操作,其格式如下。
其中,BI是指before image,AI是指after image。
咱们只要依次遍历修正前的数据和修正后的数据,并逐一调换即可。因此整个回滚操作的难点在于回滚update语句,而update语句回滚的外围在于计算出每个AI、BI的长度。上方引见下长度以及局部字段的计算方法。
镜像长度计算
镜像是由一个个字段组成的,依据字段类型的不同,其计算长度的方法也不一样。
解析binlog中的若干个关键点
① length encoded integer
binlog中一个或许多个字节组合,区分示意了不同的含意。比如,timestamp是由固定的4个字节组成,event类型由一个字节示意;数据库名和表名最长为64个字符,即使每个字符占用3个字节,那么占用的字节数为192<255。因此最多经常使用一个字节,就可以成功实践长度示意。
但是列的实践数量,或许须要超越1个字节、2个字节、3个字节甚至8个字节去示意。假设咱们经常使用***的8个字节去示意,那么在绝大少数状况下都是糜费存储空间的。针对这种状况,length encoded integer应运而生。
比如在失掉一个varchar类型的长度时,首先读取***个字节,假设值小于251,那么varchar的长度就是***个字节示意的长度。假设***个字节的值为0xFC,那么varchar的长度是由该字节之后的后两个字节组成,以此类推。
② decimal类型
decimal是由整数局部和小数局部组成。无论是整数还是小数,每9个数字,须要4个字节。假设不是9的倍数,残余的小数位,须要的字节数如下,为繁难形容,将该相关定义为函数Fnum。
举例,关于 decimal(18,10):
闪回工具架构
在上方的章节中,引见了单个binlog event的反转方法。在通常中,咱们往往须要把某个binlog,依照指定的条件,过滤出须要的binlog,并启动反转。那么MyFlash是如何成功这些指标的呢?
解析binlog
首先把binlog文件,解析成多个event,放入到相关队列中。在成功上,为了尽或许放慢解析速度,可以让用户指定解析的开局与完结位置。把binlog文件解析成binlog event后,再判别下能否合乎指定的期间条件,若不合乎,则摈弃该event。
留意:用户可以不指定位置和期间,则解析整个文件。假设只指定期间,那么也须要从文件开局处解析,取出期间信息,再启动判别。因此,当须要回滚的binlog只占整个binlog的一小局部时,介绍经常使用指定位置。
重组event
把binlog event组成最小口头单元。在经常出现的binlog event中table_map event蕴含了所要了表名、库名等元数据信息,而row_event(蕴含write_event、delete_event、update_event)蕴含了真正的数据。因此在设计中经常使用了一个最小口头单元概念。所谓的最小口头单元,即least execution event unit,通常蕴含一个table_map event和若干个row_event。
比如在binlog格式概览一节中,引见了table_map_event和update_row_event。假设只要update_row_event,那么咱们无法知道这个event对应的行记载变卦对应的表。因此一个完整的最小口头单元起码蕴含一个table_map_event和write_row_event、update_row_even、delete_row_event中的一个。
为什么咱们须要经常使用最小口头单元?由于咱们在闪回操作时,不能繁难的把每个event反转之后,而后再将一切event的顺序反转上来。假设这样的话,就会产生table_map event在row event之后,这显然是违犯binlog口头逻辑的。
有了最小口头单元之后,只要两步,即可成功反转。
a. 反转最小口头单元中的row event。
b. 逆序最小口头单元队列,即可。
当然在反转前,也可以参与过滤操作。比如过滤库名、表名和SQL类型等。
生成binlog文件
有了逆序的最小口头单元队列后,只要把每个最小口头单元依次输入到文件即可。不过不要忘了修正每个binlog event里的next_position,用来示意下一个binlog的位置。
性能对比
测试场景
经常使用testFlashback2,拔出100万条数据:
`id``nameShort``nameLong``amount``amountFloat``amountDouble``createDatetime6`datetime(6)`createDatetime`datetime`createTimestamp`mysql>+++1row
测试结果
从上述图表中可以看出,MyFlash的速度最快。