MySQLbinlog日志03binlog日志字节码解析

Posted coe2coe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQLbinlog日志03binlog日志字节码解析相关的知识,希望对你有一定的参考价值。

本系列博客主要介绍mysql数据库的binlog日志的相关内容,这个系列的主题包括:

MySQLbinlog日志01binlog日志基本操作

MySQLbinlog日志02binlog日志用于数据恢复

MySQLbinlog日志03binlog日志字节码解析

MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件

 

本博客主要内容包括:

binlog事件类型

binlog事件头部结构

binlog字节码分析的准备工作

binlog日志文件MAGIC代码

Format desc事件

Table map事件

 

下一篇博客

MySQLbinlog日志04binlog日志字节码解析之二Write_Rows事件

将介绍:

Write rows事件

 

 

1. binlog事件类型

 

MySQL Server 5.7.22支持的事件类型如下所示,总共定义了38种。

 

  START_EVENT_V3= 1,

 

  QUERY_EVENT= 2,

 

  STOP_EVENT= 3,

 

  ROTATE_EVENT= 4,

 

  INTVAR_EVENT= 5,

 

  LOAD_EVENT= 6,

 

  SLAVE_EVENT= 7,

 

  CREATE_FILE_EVENT= 8,

 

  APPEND_BLOCK_EVENT= 9,

 

  EXEC_LOAD_EVENT= 10,

 

  DELETE_FILE_EVENT= 11,

 

  NEW_LOAD_EVENT= 12,

 

  RAND_EVENT= 13,

 

  USER_VAR_EVENT= 14,

 

  FORMAT_DESCRIPTION_EVENT= 15,

 

  XID_EVENT= 16,

 

  BEGIN_LOAD_QUERY_EVENT= 17,

 

  EXECUTE_LOAD_QUERY_EVENT= 18,

 

  TABLE_MAP_EVENT = 19,

 

  PRE_GA_WRITE_ROWS_EVENT = 20,

 

  PRE_GA_UPDATE_ROWS_EVENT = 21,

 

  PRE_GA_DELETE_ROWS_EVENT = 22,

 

  WRITE_ROWS_EVENT_V1 = 23,

 

  UPDATE_ROWS_EVENT_V1 = 24,

 

  DELETE_ROWS_EVENT_V1 = 25,

 

  INCIDENT_EVENT= 26,

 

  HEARTBEAT_LOG_EVENT= 27,

 

  IGNORABLE_LOG_EVENT= 28,

 

  ROWS_QUERY_LOG_EVENT= 29,

 

  WRITE_ROWS_EVENT = 30,

 

  UPDATE_ROWS_EVENT = 31,

 

  DELETE_ROWS_EVENT = 32,

 

  GTID_LOG_EVENT= 33,

 

  ANONYMOUS_GTID_LOG_EVENT= 34,

 

  PREVIOUS_GTIDS_LOG_EVENT= 35,

 

  TRANSACTION_CONTEXT_EVENT= 36,

 

  VIEW_CHANGE_EVENT= 37,

 

  XA_PREPARE_LOG_EVENT= 38,

 

 

 

对于使用binlog日志文件进行数据恢复来说,下面4个事件非常重要:

 

TABLE_MAP_EVENT = 19,  将数据库名和表名和表id关联起来。

 

  WRITE_ROWS_EVENT = 30, INSERT语句使用。 

 

  UPDATE_ROWS_EVENT = 31,UPDATE语句使用。

 

  DELETE_ROWS_EVENT = 32,DELETE语句使用。

 

后面这三种事件处理方式非常类似,都是基于Rows_event,即包含记录行数据。

 

 

 

  

 

1. binlog事件头部结构

 

binlog事件具有相同的头部结构,总共19个字节。下表中偏移和长度均为十进制整数。

 

偏移

长度

字段

0

4

时间戳

4

1

事件类型

5

4

MySQL server-id

9

4

本事件的长度

13

4

下一个事件的开始位置

17

2

标志

 

 

上面表格中偏移量13长度4字节的字段,在<<MySQL Internals Manual>>(2006)文件中描述如下:

 

 技术分享图片

 

 

 

 

事件头部结构中的这个字段在MySQL Server 5.7.22源代码中的注释:

 

 技术分享图片

 

事件头部结构在MyFlash工具的源代码中定义如下(2019,适用于v4版本的binlog):

 技术分享图片

 

从后面的分析中可以看到,在MySQL Server 5.17..22版本产生的binlog日志文件中,认为是下一个事件的开始位置更为合适。这个字段的作用主要是用于在整个文件中快速的遍历各个事件从而找到特定的事件。

 

 

1. binlog字节码分析的准备工作

本文的目标是通过解析MySQL数据库的binlog日志文件的字节码来了解binlog日志文件的格式。

 

目标binlog文件:mysql_binlog.000003

为了分析方便,复制为all.binlog,通过hexdump程序取得十六进制格式的文本文件all.hex,通过mysqlbinlog程序取得对应的sql文件。

 

[[email protected] binlog]# ls -l all.*

-rw-r-----. 1 root root 10015 Sep 21 17:58 all.binlog

-rw-r--r--. 1 root root 49462 Sep 21 17:45 all.hex

-rw-r--r--. 1 root root 36776 Sep 21 17:43 all.sql

 

1. binlog日志文件MAGIC代码。

 

bin日志文件的magic代码的值在MySQL Server 5.7.22源代码中的定义如下:

 技术分享图片

 

binlog日志文件的前面4个字节是固定的magic代码,内容为“.bin”。

 技术分享图片

 

 

1. Format desc事件

每个binlog日志文件的第1个事件总是Format_desc

 

mysql> show binlog events in ‘mysql_binlog.000003‘ limit 1G

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

   Log_name: mysql_binlog.000003

        Pos: 4

 Event_type: Format_desc

  Server_id: 101

End_log_pos: 123

       Info: Server ver: 5.7.22-log, Binlog ver: 4

 

通过binlog文件的字节码可以分析第1个事件的内容。

下面通过分析第1个事件的事件头部结构。

技术分享图片

时间戳:

mysql> select from_unixtime(0+0x5ba39a5c);

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

| from_unixtime(0+0x5ba39a5c) |

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

| 2018-09-20 21:02:20         |

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

1 row in set (0.00 sec)

 

事件的字节数大小,以及事件的结束位置,以及下一个事件的开始位置:

mysql> select 0+0x77, 4+0x77 , 0+0x7b;

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

| 0+0x77 | 4+0x77 | 0+0x7b |

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

|    119 |    123 |    123 |

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

1 row in set (0.00 sec)

 

 

因此,第1个事件的事件头部结构的各个字段的值如下:

字段

字节码

时间戳

5c9aa35b

2018-09-20 21:02:20   

事件类型

0f

15

MySQL server-id

65000000

101

本事件的长度

77000000

119

下一个事件的开始位置

7b000000

123

标志

0000

0

 

这个事件的事件头信息与前面show binlog events 的结果是一致的。

show binlog events 的结果中pos是这个事件的事件头结构的开始位置,即在整个文件中的偏移量,第1个事件,因此偏移量总是4。 End_log_pos是这个事件的所有数据的最后一个字节之后的那个字节的位置,即下一个事件的事件头结构的开始位置。

这个事件的长度是119,这个长度包括事件头结构和事件具体内容两个部分。

 

现在需要了解Format Desc事件的内容部分的具体格式:

MySQL Server 5.7.22版本的源代码中找到了以下的注释:

技术分享图片

 

似乎显示binlog日志是v4版本的,但是其中的基类的名字似乎显示binlog日志是v3版本的。

 技术分享图片

看到下面这段注释终于明白了。MySQL Server V5.7.22binlog日志是V4版本的,只是这个Format_desc 事件是从Start_event_v3派生而来的。

 技术分享图片

 

至此,Format Desc事件的具体内容的格式已经清楚了:

 

由于事件的头部结构的长度固定为19个字节,因此,此处的第1个字段的事件内部偏移为19

事件偏移

长度

字段

19

2

binlog版本号

21

50

Server版本信息

71

4

创建时间戳

75

1

头部结构的长度

76

N

 

 

 

现在来观察这个Format Desc事件的具体内容部分。

具体内容部分的开始位置和结束位置如下所示:

mysql> select hex(4+19),hex(4+119-1);

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

| hex(4+19) | hex(4+119-1) |

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

| 17        | 7A           |

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

1 row in set (0.01 sec)

即下图中灰色部分所示区域。

技术分享图片

 

计算时间戳的偏移量:

mysql> select hex(4+71);

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

| hex(4+71) |

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

| 4B        |

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

1 row in set (0.00 sec)

 

转换为human-readable时间:

mysql> select from_unixtime(0x5ba39a5c);

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

| from_unixtime(0x5ba39a5c) |

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

| 2018-09-20 21:02:20       |

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

1 row in set (0.00 sec)

 

 

前面介绍的事件头部结构(19个字节固定长度)对每个事件来说都是相同的结构相同的长度,称之为common Header

binlog事件的事件相关头部的长度,事件相关头部即具体某个事件特有的结构,称之为Post Header

 

事件类型的长度数组:

存储本MySQL Server支持的每一种事件的Post Header Length,即事件相关头部的长度。前面已经介绍过,总共38种类型的事件,因此这个数组总共更有38个元素,总共占用38个字节。

技术分享图片

 

上图中灰色标记区域即是这个数组的内容。

由于Format Desc事件的事件类型是15,因此这个事件的Post Header Length0x5f,即十进制的95。可以这样来验证:

mysql> select 2+50+4+1+38;

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

| 2+50+4+1+38 |

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

|          95 |

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

1 row in set (0.00 sec)

上述元素的各项即Format Desc 事件的事件相关头部的各个组成部分的长度。

因此,Format Desc事件的具体内容部分的各个字段的值总结如下:

 

字段

字节码

binlog版本号

0400

4

Server版本信息

352e372e32322d6c6f6700 .....

5.7.22-log

创建时间戳

5c9aa35b

2018-09-20 21:02:20

头部结构的长度

13

19

事件类型数组

省略

省略

 

 

 

 

 

 

 

前面已经了解这个事件的总长度是119个字节,刚刚介绍都是事件的头部:Common HeaderPost Header,总共95个字节。 可以发现实际数据显示出多了5个字节:

 

mysql> select 19+95, 119-(19+95);

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

| 19+95 | 119-(19+95) |

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

|   114 |           5 |

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

1 row in set (0.00 sec)

技术分享图片

 

5个字节的具体内容是什么,稍后介绍。

 

下面进一步了解一下多出来的5个字节的真正的内容是什么。

找到了以下这个代码片段:

技术分享图片

 

95个字节之后还写入了一个字节,这个字节用于指示是否使用校验码。这个字节的具体定义如下所示:

技术分享图片

 

从前面的字节码截图可以看到,此处该值为1,即使用CRC32校验。 在这个write函数中并没有填充紧接着的4个字节,猜想有可能在其它地方处理了4个字节。

 马上看到了这个代码片段:

技术分享图片

 

其中定义了一个CRC32的签名长度,正好4个字节。因此多出来的4个字节有可能是CRC32签名的结果。

 

技术分享图片

至此,Format Desc事件字节码分析完毕。

 

Write rows事件将在下一篇博客中介绍。

 

 

 

 

 

以上是关于MySQLbinlog日志03binlog日志字节码解析的主要内容,如果未能解决你的问题,请参考以下文章

MySQLbinlog日志01binlog日志基本操作

MySQLbinlog日志02binlog日志用于数据恢复

mysql binlog日志 切换

Mysql的binlog日志与mysqlbinlog命令

mysql 利用binlog日志恢复问题

使用mysqlbinlog提取二进制日志