MySQL Row格式Binlog的解析(1)

用MySQL 行格式的复制的Slave经常会遇到复制出错1062和1032 错误,一般是镜像异常宕机导致主从复制数据不一致所致,但是有些库本身很大,重建成本很大,并且这些库的数据一致性用户可能都不是太关心的,所以之前的处理办法一般是遇到主键冲突的就跳过,遇到找不到key的就用mysqlbinlog解析一下 把数据补出来,但是这种方法太人肉话,处理起来很慢,所以之前做过一个自动修数据的工具,也是解析binlog日志,然后生成SQL语句去执行。
做这个工具还有另外一个用途,既然能解析BINLOG日志,这样也可以做基于BINLOG的恢复,当然这个功能之前阿里也有人做过,但是做的方法不太一样,可以参考MySQL的 flashback.

解析BINLOG需要知道一下几点:

  1. 出现异常的start-position
  2. 异常结束的end-position

因为是在Slave机器上运行,所以这里解析的全部都是relay log.

通过show slave status 可以清楚的知道

  • start-psoition: Relay_Log_Pos
  • end-position : 这个信息并不能直接从show slave status  里面获得,这个要算一下,计算方法:

end-position = Relay_Log_Pos + (end_log_pos - Exec_Master_Log_Pos)

(end_log_pos - Exec_Master_Log_Pos) 这个就代表这个事物从开始到出错执行的字节数。

end_log_pos  在show slave status 的错误信息里面也有,取出来就可以了。

知道了起始位置和结束位置,剩下的就可以解析了。如果不清楚binlog event的可以看下官方文档:
http://dev.mysql.com/doc/internals/en/binlog-event.html 写代码的过程中也大量参考了文档。

我使用python进行解析的,其实用什么语言都一样,步骤如下:

  1. 首先seek到起始位置
  2. 解析第一个event type ,如果是table_map_event 开启解析,如果不是就跳过,因为如果是一个正常的语句在ROW格式里记录的方式肯定是table_map_event + 具体的操作,所以如果第一个不是table_map_event 那么要么就是binlog有损坏 要么就是起始位置不对。
  3. 如果解析到了tabl_map_event,下面对我们有用的event类型也就三个:insert event / update event /delete event, 当解析掉这个event 我们基本上就可以拼凑出一个SQL语句了。
  4. 然后继续解析下一个table_map_evnt 以此类推,就能解析出很多个SQL语句。

基本过程就是这样,那么怎么解析呢

首先说说event:
  基本上所有的event 格式都是一样的,都是由header + data 这两部分组成。
header 里面都是固定的,不同的event可变部分在DATA里面。

DATA分为fixed part 和variable part.

header  格式
          | timestamp(0:4)| type_code(4:1)| server_id(5:4)| event_length(9:4)| next_position(13:4) | flags(17:2)| extra_header(19:x-19)|
data 格式
         |fix_data x:y  |  variable_data

header 说明 :

  • timestamp 时间戳
  • type_code  event类型 很有用
  • server_id 没啥用
  • event_lenght 整个event长度包括header
  • next_position   下个event的position 很有用
  • flags 没用
  • extra_header 这个目前都没啥用

所以整个header一共19字节,DATA部分占用字节数:event_length - 19

下面说一下几种用到的BINLOG格式:

  • TABLE_MAP_EVENT: 19
  • WRITE_ROWS_EVENT : 23
  • UPDATE_ROWS_EVENT : 24
  • DELETE_ROWS_EVENT :  25

这里要注意一下,从MySQL5.6.2 开始 event的type 变化了,所以导5.6的需要改一下,5.6的我还没有详细的测试过,不知道还有什么坑。

  • #mysql5.6.2 events
  • # WRITE_ROWS_EVENT= 30
  • # UPDATE_ROWS_EVENT= 31
  • # DELETE_ROWS_EVENT= 32
  • # INCIDENT_EVENT= 26

因为header部分都一样,所以直接说DATA部分了。

TABLE_MAP_EVENT

Data:

Fixed data:

  • Table_id (6bytes)
  • extra  not use (2bytes)

Variable data

  • Schema_length (1bytes)
  • Schame name (Schema_length  size )
  • 0  //空字符占一字节
  • Table length (1bytes)
  • Table name (table length size)
  • 0  //空字符占一字节
  • Column size (变长,最多存8个byte,最大为2的64次方)
  • Coulmn type (column size bytes )

我们能从table_map_event 里面得到什么?

  没错 主要能得到的就是库名和表名还有字段类型

表明和库名都好弄,直接读出来不用转,字段类型MySQL还有一个专门的转换表,每一个字节对应一个字段类型。
http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::MYSQL_TYPE_DATETIME
那么现在表表库名字段类型都有了,感觉还少了字段名称,字段名称直接去MySQL里面去查。

sql = ("select * from information_schema.columns where table_schema=‘%s’"
           " and table_name=‘%s’")

这样我们这些元数据信息都有了,就需要解析具体的数据了,然后把解析好的数据直接填进去。

那么下面就只剩下如何解析别的event格式了。

先从WRITE_ROWS_EVENT 开始:
WRITE_ROWS_EVENT 其实就是一个insert操作,前面也说过每一份event的header都是一样的,只是DATA部分有区分而已,所以WRITE_ROWS_EVENT也一样,header部分为19字节,DATA部门为event_length-19字节。

那么DATA部分中的fixed data 和variables data各是什么呢?

Fixed data :

  • Table_id (6bytes)
  • extra  not use (2bytes)

Variables data :

  • col_num  (dynamic),一般是1bytes.
  • map_col (table bitmap)
  • Record

可以看到fixed data 部分有用的信息不多,可能table_id 还有些用,重要的在variables data 部分。

  • col_num  代表字段的个数占用字节数是可变的,一般一字节就够了,1字节/2的八次方 一般也很难有表有几百个字段。
  • map_col  这个代表字段是否为空
  • Record  这个就是具体的记录内容。

怎么解析Record?

Record的格式是bit_map + record 的结构。
bit_map 的每一位代表字段是否为空,所以bit_map占用的字节数为:((columns+7)/8)
比如1100 代表一共四个字段,前两个字段为非空,后两个为NULL,为NULL的数据在record里面是不记录的。
所以呢,首先根据bitmap 判断字段是否为空,如果不为空则拿程序继续往下扫描,如果为空则判断下一个字段是否为空。
至此一个insert语句基本上是解析完了。
除此之外DELETE_ROWS_EVENT 基本上和insert一样。
UPDATE_ROWS_EVENT 稍微有一点点特别,UPDATE_ROWS_EVENT 也是bitmap + record ,但是Update包含更新前像和后像,所以一条Update的格式为
bitmap + record (前像) + bitnap + record (后像)

基本上简单的一条语句就是这样:
table-map-event + insert/update/delete event
那么可能会出现这样的情况比如:
insert values (),(),()  或者delete id in (…)
一条SQL操作很多条记录的情况。
那么这种record 的格式就变成 record = (bitmap + data) +  (bitmap + data) .. 直到解析完为止

所以扫描的时候一定要把这个event扫描完,不然很容易出错。

这里先简单的介绍一下如何解析BINLOG吧,下面会再详细解析如何解析各个不同类型的字段。

MySQL Row格式Binlog的解析(1),布布扣,bubuko.com

时间: 2024-10-10 01:15:41

MySQL Row格式Binlog的解析(1)的相关文章

ROW 格式binlog 在MySQL5.6上的数据恢复实验

ROW 格式的binlog 在MySQL5.6上的数据恢复实验 5.6和5.7版本的MySQL,有个参数binlog_row_image,默认值为FULL,表示记录的是全部的binlog操作日志(仅在binlog_format=ROW时候生效).此外binlog_row_image还可以是minimal,表示binlog记录的就只是影响后的行.如此一来使用ROW格式就能节约很多的磁盘空间. 因此,我们服务器上就可以直接设置binlog_format=ROW格式了,至于binlog_row_ima

MySQL如何记录binlog

--MySQL如何记录binlog   -------------------------------2014/07/08 binlog文件的内容 log event    MySQL的binlog文件中记录的是对数据库的各种修改操作,用来表示修改操作的数据结构是Log event.不同的修改操作对应的不同的log event.比较常用的几种log event有:Query event.Row event.Xid event等.其中Query event对应的是一条SQL语句,在DDL操作和ST

【20180507】MySQL主从在线修改从库binlog格式从STATEMENT更改成ROW格式

需求 公司内部有几十套基于传统复制的MySQL主从实例,而且binlog的格式都是STATEMENT格式.在接手这些MySQL主从实例之后就有考虑过想将binlog格式更改成ROW格式.而这次则是因为我们elk上面一个第三方工具需要解析和监听binlog信息,并且只能解析ROW格式的binlog,借此机会正好将公司部分MySQL主从复制实例的binlog格式更改成ROW格式. ROW和STATEMENT比对 row格式 优点:就是能够完全保证主从数据的一致性,不会出现因为在SQL中使用MySQL

mysql binlog row格式查看

MySQL 5.1开始,binlog支持row-based的格式,默认情况下只能看到一些经过base-64编码的信息,如 DELIMITER /*!*/; # at 7493962 #090827 5:25:03 server id 1 end_log_pos 0 Start: binlog v 4, server v 5.1.26-rc-community-log created 090827 5:25:03 BINLOG ' L6iVSg8BAAAAZgAAAAAAAAAAAAQANS4xL

MySQL Binlog Mixed模式记录成Row格式

概念: binlog format有三种形式:Statement.Mixed.Row,具体的信息可以自行到网上搜查. 分析(本文碰到的案例): 查看MySQL binlog format [email protected] : dba_test 02:33:39>show variables like 'binlog_format%';                                                                                

mysql row日志格式下 查看binlog sql语句

有时候我们需要使用row作为binlog的日志格式,即配置文件使用了binlog_format= row 参数 这样以来,我们在查看数据库binlog内容时候,就看不到增删改查的具体语句了,在数据库恢复的时候 不利于我们查找恢复数据点. 使用row日志格式的日志: 可以看到都是一段段类似加密过的字符串一样,不要着急,其实sql真实语句就在这里这里,只不过 是经过64位编码转换后的内容,我们使用mysqlbinlog对应的参数即可查看具体的sql内容: mysqlbinlog --base64-o

20180705关于mysql binlog的解析方式

来自:https://blog.csdn.net/u012985132/article/details/74964366/ 关系型数据库和Hadoop生态的沟通越来越密集,时效要求也越来越高.本篇就来调研下实时抓取MySQL更新数据到HDFS. 本篇仅作为调研报告. 初步调研了canal(Ali)+kafka connect+kafka.maxwell(Zendesk)+kafka和mysql_streamer(Yelp)+kafka.这几个工具抓取MySQL的方式都是通过扫描binlog,模拟

MySQL在线更改binlog格式

今天变更jboss报错如下: SQLWarning ignored: SQL state 'HY000', error code '1592', message [Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements writing to a table with an auto-increment column after sel

Mysql数据库之Binlog日志使用总结

binlog二进制日志对于mysql数据库的重要性有多大,在此就不多说了.下面根据本人的日常操作经历,并结合网上参考资料,对binlog日志使用做一梳理: 一.binlog日志介绍1)什么是binlogbinlog日志用于记录所有更新了数据或者已经潜在更新了数据(例如,没有匹配任何行的一个DELETE)的所有语句.语句以"事件"的形式保存,它描述数据更改. 2)binlog作用因为有了数据更新的binlog,所以可以用于实时备份,与master/slave主从复制结合. 3)和binl