230_mysql_binlog结构组成

举报
alexsully 发表于 2021/11/16 03:46:04 2021/11/16
【摘要】 binlog_event结构和组成

MySQL binlog event类型

https://dev.mysql.com/doc/internals/en/event-meanings.html

enum Log_event_type
{ UNKNOWN_EVENT= 0,
  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,
  ENUM_END_EVENT /* end marker */
};

1 常见binlog_event类型

event类型含义

 

FORMAT_DESCRIPTION_EVENT

每个binlog文件开头的一个event, 记录binlog的版本,数据库版本,创建时间等基本信息

ROTATE_EVENT

1切换新binlog文件:执行FLUSH LOGS语句 or binlog达阈值max_binlog_size意外宕机重启后会新生成binlog

2 切换新的binlog文件的时候,MySQL会在旧的binlog文件中写入一个ROTATE_EVENT,表示新的binlog文件的文件名,以及第一个偏移地址。

3宕机前最后一个binlog不是 ROTATE_EVENT结尾

数据库变更事件

 

TABLE_MAP_EVENT

TABLE_MAP_EVENT只有在binlog文件是以ROW格式记录的时候,才会使用。binlog中记录的每个更改的记录之前都会有一个对应要操作的表的TABLE_MAP_EVENTTABLE_MAP_EVENT中记录了表的定义(包括database name,table name,字段定义),并且会将这个表的定义对应于一个数字,称为table_id。设计TABLE_MAP_EVENT类型event的目的是为了当主库和从库之间有不同的表定义的时候,复制仍能进行。如果一个事务中操作了多个表,多行记录,在binlog中会将对多行记录的操作event进行分组,每组行记录操作event前面会出现对应表的TABLE_MAP_EVENT

QUERY_EVENT

QUERY_EVENT以文本的形式来记录事务的操作

QUERY_EVENT类型的事件通常在以下几种情况下使用:

事务开始时,执行的BEGIN操作。

STATEMENT格式中的DML操作。

ROW格式中的DDL操作。

ROWS_EVENT

对于ROW格式的binlog,所有的DML语句都是记录在ROWS_EVENT中。
ROWS_EVENT
分为三种:WRITE_ROWS_EVENTUPDATE_ROWS_EVENTDELETE_ROWS_EVENT

对于QUERY_EVENT事件,是以文本形式记录DML操作的。而对于ROWS_EVENT事件,并不是文本形式,所以在通过mysqlbinlog查看基于ROW格式的binlog时,需要指定-vv --base64-output=decode-rows

WRITE_ROWS_EVENT

UPDATE_ROWS_EVENT

DELETE_ROWS_EVENT

在以ROW格式记录的binlog文件中,WRITE_ROWS_EVENT记录了插入的行记录

在以ROW格式记录的binlog文件中,UPDATE_ROWS_EVENT记录了更新的行记录

在以ROW格式记录的binlog文件中,DELETE_ROWS_EVENT记录了删除的行记录

HEARTBEAT_LOG_EVENT

master发给slave的,让slave知道master还活着。这类事件不会在binlogrelay log中出现。

他们由masterdump事件线程产生,然后直接发给了slaveslave收到后,校验事件内容后,直接抛弃这个事件,而不会写到relay log

2 event字节解析

MySQL的发展过程中,一共出现过三个版本的event结构:

v1:MySQL 3.23中使用

v2:MySQL4.0.24.1中使用

v4:MySQL5.0及以上版本中使用

3 event组织架构

v4版本的event主要由event header部分和post-header以及variable part部分组成。

event组织架构

 

event header

是每个event都会有的部分,并且每个event header的格式是相同的,固定为19个字节长度,在event header 中记录了event_lengthtype_code等信息,可以表示event的长度,event的类型,下一个event的偏移位置等信息,都可以再event header中获取到。

extra_headers

指定了除公共头部外的内容,但是目前版本的binlog格式中,这一部分不存在的

fixed_part & post-header

每个类型的event之间的post-header部分是不相同的,但是同一类型的event占用的post-header

字节数是一样的。每个类型的event占用多少字节为post-header,这个定义在了Format_description_event

variable part & body

event真实记录具体信息的部分;part有些时候也被称作payload或者body

event字节结构表示如下

timestamp记录的是该事务记录的时间

type_code,记录的是该event的类型,具体的event类型,见上面的Log_event_type

server_id,记录的是执行该eventserverserver_id

event_length,该event的长度,共占多少字节

next_position,下一个eventbinlog文件中的偏移位置

flag:标记

extra_headers,额外的头部内容,现在是空的,不存在

fixed part有些时候也被称作post-header

variable part有些时候也被称作payload或者body

event公共头部

从上述的event结构中,可以看到,每个eventheader部分的内容结构是一致的,所有的event,都会记录这些信息,这是所有的event的公共头部分

字段

字节数

描述

timestamp

4字节

时间戳

type_code

1字节

记录event类型

server_id

4 字节

记录event生成的MySQL所对应的server_id

event_length

4字节

这个event的字节长度,包括event header

next_position

4字节

下一个eventbinlog文件中的偏移位置

flags

2字节

 

b6 1e 1c 5a //timestamp:小端存储,将16进制转换成10进制为1511792310,将时间戳转换为时间为2017-11-27 22:18:30
1e //type_code:event类型,0x1e转换为10进制为30,查看Log_event_type中,看到30的为WRITE_ROWS_EVENT
0f 27 00 00 //server_id :小端存储,将16进制转换为10进制为9999
31 00 00 00 //event_length :小端存储,将16进制转换为10进制为49
b1 03 00 00 //next_position:小端存储,将16进制转换为10进制为945
00 00 //flags:
body部分省略

Format_description_event

Format_description_event是每个binlog文件开头的一个描述信息的event

fixed part (post-header) 部分

字段       

字节数   

描述

binlog_version

2字节    

binlog结构的版本,v1,v2,v4

server_version

50字节

MySQL server的数据库版本

timestamp

4字节

创建该binlog文件的时间,单位为秒

header_length

1字节

指定公共头部的长度,v4版本中这个值一直为19,说明其他所有的eventextra_header部分都是空, extra_header长度为header_length-19

event_post_header_length

variable size跟各个版本支持的event类型总数一致

每个event类型,占用一个字节,表示该event类型post-header部分的长度

Variable part (event-body)部分

字节解析示例
公共头部部分省略
04 00 //binlog_version :v4版本
35 2e 36 2e 33 34 2d 6c 6f 67 
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00  //mysql server version :16进制转换为ascii之后,值为5.6.34-log
00 00 00 00 //timestamp:
13 //header length :19,说明该版本的event类型公共头部长度都为19,extra_header长度为header_length-19
38 0d 00 08 00 12 00 04 04 04 
04 12 00 00 5c 00 04 1a 08 00 
00 00 08 08 08 02 00 00 00 0a 
0a 0a 19 19 00 //event_post_header_len:各个类型event的post-header部分长度
01 2e ef 23 e2

Rotate_event

MySQL切换至新的binlog文件的时候,MySQL会在旧的binlog文件中写入一个ROTATE_EVENT,其内容包含新的binlog文件的文件名以及第一个偏移地址。当在数据库中执行FLUSH LOGS语句或者binlog文件的大小超过max_binlog_size参数设定的值就会切换新的binlog文件。

fixed part (post-header) 部分

字段       

字节数   

描述

next_binlog_po

8字节

下一个binlog文件起始的偏移地址

 

Variable part (event-body)部分

字段       

字节数   

描述

next_binlog_filename

variable string

下一个binlog文件的文件名

字节解析示例
公共头部部分省略
04 00 00 00 00 00 00 00 //next_binlog_pos:下一个binlog的起始偏移地址,小端存储,16进制转换为10进制之后为4
6d 79 73 71 6c 2d 62 69 6e 2e 30 30 30 30 30 32  //next_binlog_filename:下一个binlog的文件名,16进制转换为ascii之后,值为mysql-bin.000002
b3 db 0b 9a checksum

Query_log_event

记录更新操作的语句

fixed part (post-header) 部分

字段       

字节数       

描述

thread_id

4字节       

执行语句的线程ID

exec_time

4字节

语句执行的时间

db_len

1字节

database名的长度

error_code

2字节

错误号

status_vars_len

2字节

v1v3版本的event中是没有的,指定状态值的长度

 

Variable part (event-body)部分

字段       

字节数   

描述

status_vars

status_vars_len字节       

记录状态值,具体的解析见下表

database_name

db_len+1字节

null-terminaled类型的字符串,记录database的名字

query_statement   

不定       

执行的语句

check_sum

4字节

校验码

status_vars的解析是,一个字节表示状态的类型,在类型之后按照类型不同紧接着不同字节数的状态值,状态的类型对应状态码以及字节数

enum Query_event_status_vars
  {
    Q_FLAGS2_CODE= 0,   #4字节
    Q_SQL_MODE_CODE= 1,    #8字节
    Q_CATALOG_CODE=2,     #第一个字节表示catalog_len,总共catalog_len+2个字节
    Q_AUTO_INCREMENT=3,   #4字节
    Q_CHARSET_CODE=4,     #6字节
    Q_TIME_ZONE_CODE=5,   #第一个字节表示time_zone_len,总共time_zone_len+1字节
    Q_CATALOG_NZ_CODE=6,  # 第一个字节表示catalog_len,总共catalog_len+1个字节
    Q_LC_TIME_NAMES_CODE=7, #2字节
    Q_CHARSET_DATABASE_CODE=8,  #2字节
    Q_TABLE_MAP_FOR_UPDATE_CODE=9, #8字节
    Q_MASTER_DATA_WRITTEN_CODE=10,  #4字节
    Q_INVOKER =11,  #包含两部分,一部分是user,一部分是host。user部分,一个字节表示user_len,接着user_len个字节表示user。host部分,一个字节表示host_len,接着host_len个字节表示host
    Q_UPDATED_DB_NAMES=12, 
    Q_MICROSECONDS =13, 3字节
    Q_COMMIT_TS=14,
    Q_COMMIT_TS2=15,
    Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP=16 1字节
  };

解析二进制文件
公共头部部分省略。。。。
a4 9f 01 00 //thread_id:执行语句的线程号,小端存储,转换为16进制为106404
00 00 00 00 //exec_time:执行语句的时间,小端存储,转化为16进制为0
08 //db_len:database name的长度,转换为10进制为8
00 00 //error_code:错误号,小端存储,转换为10进制为0
2a 00 //status_vars_len:状态值的长度,小端存储,转换为10进制为42,表示后续的42个字节为状态值的内容
//status_vars_len
00 00 00 00 00 
01 00 00 20 40 00 00 00 00
06 03 73 74 64 
03 02 00 02 00
04 21 00 21 00 53 00 
0c 01 67 61 6e 67 73 68 65 6e 00 
67 61 6e 67 73 68 65 6e 00 //database_name:数据库名称,null-terminaled string类型 ,转换为字符串为gangshen
696e7365727420696e746f20746573743128606e616d6560292076616c75657328276265696a696e672729 //query_statement:执行的语句,转换为字符串为:insert into test1(`name`) values('beijing')
21 92 37 98//checksum

Rows_query_log_event

row格式复制模式下,将query以语句形式记录。在5.6.2版本之后,可以通过设置binlog_rows_query_log_events参数来控制在row格式复制模式下是否需要将query语句记录到binlog文件中。

fixed part (post-header) 部分

Variable part (event-body)部分

字段       

字节数   

描述

str_len

1字节    

记录语句长度

statement

str_len字节

对应的语句

checksum       

4字节

校验码

解析二进制文件:

公共头部部分省略。。。
2e //str_len:执行语句的长度,转换为10进制为46
696e7365727420696e746f20746573743128606e616d6560292076616c7565732827726f77735f71756572792729  //statement:执行的语句,转换为ascii为insert into test1(`name`) values('rows_query')
8a af 68 dc //check_sum

Table_map_event

TABLE_MAP_EVENT只有在binlog文件是以ROW格式记录的时候,才会使用。binlog中记录的每个更改的记录之前都会有一个对应要操作的表的TABLE_MAP_EVENT。

TABLE_MAP_EVENT中记录了表的定义(包括database name,table name,字段定义),并且会将这个表的定义对应于一个数字,称为table_id。

设计TABLE_MAP_EVENT类型event的目的是为了当主库和从库之间有不同的表定义的时候,复制仍能进行。

如果一个事务中操作了多个表,多行记录,在binlog中会将对多行记录的操作event进行分组,每组行记录操作event前面会出现对应表的TABLE_MAP_EVENT

 

fixed part (post-header) 部分

字段       

字节数   

描述

table_id

6字节    

操作的表的table_id

flags

2字节

目前版本没有用,都是0,保留给之后的版本使用

Variable part (event-body)部分

字段       

字节数   

描述

database_name

1个字节表示字符串长度,之后接一个null-terminated类型的字符串

操作的数据库的名称

 

dtable_name  

1个字节表示字符串长度,之后接一个null-terminated类型的字符串

操作的表的名称

column_count

packed integer(1349个字节)

对应表中的字段数量

column_type

每个字段占用一个字节,字段类型定义在enum_field_types

字段类型

metadata_length

packed integer(1349个字节)

对应字段的元数据信息的长度

metadata

根据enum_field_type中的定义确定不同字段的元数据,如果某字段类型没有元数据,则不记录

每个字段的元数据信息,比如varchar字段需要记录最长长度

 

null_bits

int((column_count + 7)/8) 字节

一个bit表示一个字段是否可以为NULL,顺序是:第一个字节的最低位开始向最高位增长,之后第二个字节的最低位开始向最高位增长,以此类推

 

check_sum

4字节    

校验码

 

CREATE TABLE `test1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

二进制内容解析:

公共头部部分省略
6c 00 00 00 00 00 //table_id :小端存储,16进制转换为10进制为108
01 00 //flag :
08 67 61 6e 67 73 68 65 6e 00 //database_name :1个字节是字符串长度,后接一个null-terminated string 第一个字节表示字符串长度为8,后面内容将16进制转换为ascii字符为gangshen
05 74 65 73 74 31 00 //table_name: 1个字节是字符串长度,后接一个null-terminated string第一个字节表示字符串长度为5,后面内容将16进制转换为ascii字符为test1
02 //columns count :packet integer类型,转换之后,数值为2 表示表中有两个字段
03 0f //column type : 一个字节表示一个字段的类型,字段类型定义在enum enum_field_types ,分别是一个int类型以及一个varchar类型,具体的字段类型及记录格式等信息可以查看《MySQL中Rows_event中字段表示》文档
02 //metadata length : packet integer类型,转换之后,数值为2,表示记录表中的metadata内容占用2个字节
14 00 // :varchar 的max length 因为int没有metadata所以跳过
02 //null_bits :int((column_count + 7) / 8)个字节 一个bit表示一个字段是否可以为null 
52 53 4a d9 checksum

Write_rows_log_event

在以ROW格式记录的binlog文件中,Write_rows_log_event记录了插入的行记录

fixed part (post-header) 部分

字段       

字节数

描述

table_id

6字节

操作的表的table_id

flags

2字节

目前版本没有用,都是0,保留给之后的版本使用

Variable part (event-body)部分

字段       

字节数   

描述

var_header

2字节

 

m_width 

packed integer(1349个字节)       

表中字段数量

before_image

(m_width + 7)/8字节

对应表中的字段数量

after_bitmap_bits

(m_with +7)/8字节

字段值是否为空标记,一个bit表示一个字段是否为NULL,顺序是:第一个字节的最低位开始向最高位增长,之后第二个字节的最低位开始向最高位增长,以此类推

after_column_content

不定       

按照顺序每个字段的内容

check_sum

4字节

校验码

建表语句

CREATE TABLE `int_table` (
  `col1` tinyint(4) DEFAULT NULL,
  `col2` smallint(6) DEFAULT NULL,
  `col3` mediumint(9) DEFAULT NULL,
  `col4` int(11) DEFAULT NULL,
  `col5` bigint(20) DEFAULT NULL,
  `col6` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
插入数据:
insert into int_table values(1,11,111,1111,11111,true);
对应Write_rows_log_event使用mysqlbinlog解析
# at 340
#180103 10:21:20 server id 330619  end_log_pos 395 CRC32 0x50177e10    Write_rows: table id 100 flags: STMT_END_F
### INSERT INTO `gangshen`.`int_table`
### SET
###  @1=1 /* TINYINT meta=0 nullable=1 is_null=0 */
###  @2=11 /* SHORTINT meta=0 nullable=1 is_null=0 */
###  @3=111 /* MEDIUMINT meta=0 nullable=1 is_null=0 */
###  @4=1111 /* INT meta=0 nullable=1 is_null=0 */
###  @5=11111 /* LONGINT meta=0 nullable=1 is_null=0 */
###  @6=1 /* TINYINT meta=0 nullable=1 is_null=0 */
# at 395

公共头部部分省略
64 00 00 00 00 00 //table_id: 小端存储,16进制转换为10进制为100
01 00 //flag:
02 00 //var header length :小端存储,16进制转换为10进制为2
06 //m_width :packet integer,表示表中字段数量
ff //before image: (m_width + 7) / 8字节
c0 //after_bitmap_bits :insert插入之后的记录的NULL标记,表中六个字段,插入的值都不为NULL
//after_columns_content:insert插入记录之后的记录值
01 
0b 00 
6f 00 00 
57 04 00 00
67 2b 00 00 00 00 00 00
01 
10 7e 17 50 //checksum

Update_rows_log_event

在以ROW格式记录的binlog文件中,Update_rows_log_event记录了更新的行记录。

fixed part (post-header) 部分

字段       

字节数   

描述

table_id

6字节    

操作的表的table_id

flags

2字节

目前版本没有用,都是0,保留给之后的版本使用

 

Variable part (event-body)部分

字段       

字节数   

描述

var_header

2字节

 

m_width 

packed integer(1349个字节)  

表中字段数量

before_image

(m_width + 7)/8字节

对应表中的字段数量

after_image _image

(m_width + 7)/8字节

对应表中的字段数量

before_bitmap_bits

(m_with+7)/8字节

before_bitmap_bits记录的是update更改之前的记录中,字段值是否为NULL标记,一个bit表示一个字段是否为NULL,顺序是:第一个字节的最低位开始向最高位开始增长,之后第二个字节的最低位开始向最高位增长,以此类推

before_column_content

不定

update更新之前的记录值,按照顺序每个字段的内容

after_bitmap_bits

(m_with +7)/8字节

after_bitmap_bits记录的是update更改之前的记录中,字段值是否为NULL标记,一个bit表示一个字段是否为NULL,顺序是:第一个字节的最低位开始向最高位开始增长,之后第二个字节的最低位开始向最高位增长,以此类推

after_column_content

不定       

update更新之后的记录值,按照顺序每个字段的内容

check_sum

4字节

校验码

字节解析示例
建表语句

CREATE TABLE `int_table` (
  `col1` tinyint(4) DEFAULT NULL,
  `col2` smallint(6) DEFAULT NULL,
  `col3` mediumint(9) DEFAULT NULL,
  `col4` int(11) DEFAULT NULL,
  `col5` bigint(20) DEFAULT NULL,
  `col6` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

插入数据并更新:

insert into int_table values(1,11,111,1111,11111,true);
update int_table set col2=22,col3=222 where col1=1;

对应Update_rows_log_event使用mysqlbinlog解析

# at 644
#180103 10:41:37 server id 9999  end_log_pos 720 CRC32 0x5576b52f    Update_rows: table id 231 flags: STMT_END_F
### UPDATE `gangshen`.`int_table`
### WHERE
###  @1=1 /* TINYINT meta=0 nullable=1 is_null=0 */
###  @2=11 /* SHORTINT meta=0 nullable=1 is_null=0 */
###  @3=111 /* MEDIUMINT meta=0 nullable=1 is_null=0 */
###  @4=1111 /* INT meta=0 nullable=1 is_null=0 */
###  @5=11111 /* LONGINT meta=0 nullable=1 is_null=0 */
###  @6=1 /* TINYINT meta=0 nullable=1 is_null=0 */
### SET
###  @1=1 /* TINYINT meta=0 nullable=1 is_null=0 */
###  @2=22 /* SHORTINT meta=0 nullable=1 is_null=0 */
###  @3=222 /* MEDIUMINT meta=0 nullable=1 is_null=0 */
###  @4=1111 /* INT meta=0 nullable=1 is_null=0 */
###  @5=11111 /* LONGINT meta=0 nullable=1 is_null=0 */
###  @6=1 /* TINYINT meta=0 nullable=1 is_null=0 */
# at 720
解析二进制文件:

公共头部部分省略。。。
64 00 00 00 00 00 //table_id: 小端存储,16进制转换为10进制为100
01 00 //flag:
02 00 //var header length :小端存储,16进制转换为10进制为2
06 //m_width :packet integer,表示表中字段数量
ff //before image: (m_width + 7) / 8字节
ff //after image: (m_width + 7) / 8字节
c0 //before_bitmap_bits :update更新之前记录中NULL标记,表中六个字段,值都不为NULL
//before_column_content接下来是update更新之前记录的值
01 
0b 00
6f 00 00 
57 04 00 00
67 2b 00 00 00 00 00 00
01 
c0 //after_bitmap_bits :update更新之后记录中NULL标记,表中六个字段,值都不为NULL
//after_column_content接下来是update更新之前记录的值
01 
16 00 
de 00 00 
57 04 00 00
67 2b 00 00 00 00 00 00 
01 
16 a3 de bb //checksum

Delete_rows_log_event

在以ROW格式记录的binlog文件中,Delete_rows_log_event记录了删除的行记录。

fixed part (post-header) 部分

字段       

字节数   

描述

table_id

6字节    

操作的表的table_id

flags

2字节

目前版本没有用,都是0,保留给之后的版本使用

 

Variable part (event-body)部分

字段       

字节数   

描述

var_header

2字节

 

m_width 

packed integer(1349个字节)  

表中字段数量

after_image _image

(m_width + 7)/8字节

对应表中的字段数量

before_bitmap_bits

(m_with+7)/8字节

before_bitmap_bits记录的是update更改之前的记录中,字段值是否为NULL标记,一个bit表示一个字段是否为NULL,顺序是:第一个字节的最低位开始向最高位开始增长,之后第二个字节的最低位开始向最高位增长,以此类推

before_column_content

不定

delete删除之前的记录值,按照顺序每个字段的内

check_sum

4字节

校验码

建表语句

CREATE TABLE `int_table` (
  `col1` tinyint(4) DEFAULT NULL,
  `col2` smallint(6) DEFAULT NULL,
  `col3` mediumint(9) DEFAULT NULL,
  `col4` int(11) DEFAULT NULL,
  `col5` bigint(20) DEFAULT NULL,
  `col6` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
删除数据:

delete from int_table where col1=1;
对应Delete_rows_log_event使用mysqlbinlog解析

# at 320
#180103 14:24:54 server id 330619  end_log_pos 375 CRC32 0xce4818b2    Delete_rows: table id 100 flags: STMT_END_F
### DELETE FROM `gangshen`.`int_table`
### WHERE
###  @1=1 /* TINYINT meta=0 nullable=1 is_null=0 */
###  @2=22 /* SHORTINT meta=0 nullable=1 is_null=0 */
###  @3=222 /* MEDIUMINT meta=0 nullable=1 is_null=0 */
###  @4=1111 /* INT meta=0 nullable=1 is_null=0 */
###  @5=11111 /* LONGINT meta=0 nullable=1 is_null=0 */
###  @6=1 /* TINYINT meta=0 nullable=1 is_null=0 */
# at 375
解析二进制文件:

公共头部部分省略
64 00 00 00 00 00 //table_id: 小端存储,16进制转换为10进制为100
01 00 //flag:
02 00 //var header length :小端存储,16进制转换为10进制为2
06 //m_width :packet integer,表示表中字段数量
ff //after image: (m_width + 7) / 8字节
c0 //before_bitmap_bits :delete删除之前的记录的NULL标记,表中六个字段,值都不为NULL
//before_columns_content:delete删除记录之前的记录值
01 
16 00 
de 00 00 
57 04 00 00
67 2b 00 00 00 00 00 00
01 
10 7e 17 50 //checksum

Xid_event

表示支持内部XA的存储引擎上的事务提交。正常的事务是通过QUERY_EVENT来发送一个BEGIN语句并且通过QUERY_EVENT来发送一个COMMIT语句(如果事务回滚则发送的是ROLLBACK)实现

fixed part (post-header) 部分

Variable part (event-body)部分

字段       

字节数   

描述

xid

8字节

无符号数

after_image _image

(m_width + 7)/8字节

对应表中的字段数量

 

# at 1691

#180103 15:30:45 server id 330619  end_log_pos 1722 CRC32 0x8816181c    Xid = 2698

COMMIT/*!*/;

# at 1722


解析二进制文件:

公共头部部分省略...

8a 0a 00 00 00 00 00 00 //xid,因为是小端存储,所以实际为0x 00 00 00 00 00 00 0a 8a,转换为10进制为2698

1c 18 16 88 //check_sum

Gtid_log_event

开启GTID模式的场景下,每次事务commit提交时,MySQL会在binlog中事务开始写入一个Gtid_log_event,记录该事务的GTID事务号。

fixed part (post-header) 部分

字段       

字节数       

描述

commit_flag

1字节

标记事务是否提交,非0为已提交,为0表示,事务未提交

sid

16字节

记录GTIDuuid的部分(不记录‘-’),每1个字节表示uuid2个字符

gno

8字节

小端存储,GTID中的事务号部分

Variable part (event-body)部分

字段       

字节数       

描述

checksum        4

4字节

校验码

字节解析示例
使用mysqlbinlog工具解析binlog文件

# at 191
#180109 18:31:08 server id 330619  end_log_pos 239 CRC32 0xd20330e8    GTID [commit=yes]
SET @@SESSION.GTID_NEXT= '89fbcea2-da65-11e7-a851-fa163e618bac:5'/*!*/;
# at 239
解析二进制文件:

公共头部部分省略。。。。
01 //commit_flag:标记事务是否已提交,表示已提交
89 fb ce a2 da 65 11 e7 a8 51 fa 16 3e 61 8b ac //sid:GTID中uuid部分,转换为uuid为89fbcea2-da65-11e7-a851-fa163e618bac
05 00 00 00 00 00 00 00 //gno:GTID中的事务号,小端存储,转换为10进制为5
e8 30 03 d2 //checksum

Previous_gtid_log_event

在开启GTID的模式下,每个binlog文件开始会记录一个Previous_gtid_log_eventPrevious_gtid_log_event中会包含当前binlog之前所有binlog中的GTID集合

fixed part (post-header) 部分

字段       

字节数       

描述

n_sids

8字节

小端存储,记录之后有几个GTID中的uuid

sid

16字节

记录GTIDuuid的部分(不记录‘-’),每1个字节表示uuid2个字符

n_intervals

8字节

记录每个sid对应有几个间隔,指的是事务号间隔

start

8字节

每个事务号间隔中的起始事务号

end 

8字节

每个事务号间隔中的结束事务号+1

Variable part (event-body)部分

字段       

字节数       

描述

checksum        4

4字节

校验码

字节解析示例
使用mysqlbinlog工具解析binlog文件

# at 120
#180111 14:10:27 server id 330619  end_log_pos 279 CRC32 0x94a92478    Previous-GTIDs
# 89fbcea2-da65-11e7-a851-fa163e618bac:1-5:999:1050-1052,
# aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-2:5-7
DELIMITER ;

解析二进制文件:

公共头部部分省略。。。
02 00 00 00 00 00 00 00 //n_sids:记录之后有几个GTID中的uuid号,小端存储,转换为10进制为2,表后后续有2个uuid号
89 fb ce a2 da 65 11 e7 a8 51 fa 16 3e 61 8b ac //sid:GTID中的uuid号转换为uuid为89fbcea2-da65-11e7-a851-fa163e618bac
03 00 00 00 00 00 00 00 //n_intervals:对应的sid中中对应几个事务号间隔,小端存储,转换为10进制为3,表示有3个事务号间隔
01 00 00 00 00 00 00 00 //start:事务号间隔中的起始事务号,小端存储,转换为10进制为1
06 00 00 00 00 00 00 00 //end:事务号间隔中的结束事务号+1,小端存储,转换为10进制为6,实际的间隔结束事务号为5
e7 03 00 00 00 00 00 00 //start:事务号间隔中的起始事务号,小端存储,转换为10进制为999
e8 03 00 00 00 00 00 00 //end:事务号间隔中的结束事务号+1,小端存储,转换为10进制为1000,实际的间隔结束事务号为999
1a 04 00 00 00 00 00 00 //start:事务号间隔中的起始事务号,小端存储,转换为10进制为1050
1d 04 00 00 00 00 00 00 //end:事务号间隔中的结束事务号+1,小端存储,转换为10进制为1053,实际的间隔结束事务号为1052
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa //sid:GTID中的uuid号转换为uuid为aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
02 00 00 00 00 00 00 00 //n_intervals:对应的sid中中对应几个事务号间隔,小端存储,转换为10进制为2,表示有2个事务号间隔
01 00 00 00 00 00 00 00 //start:事务号间隔中的起始事务号,小端存储,转换为10进制为1
03 00 00 00 00 00 00 00 //end:事务号间隔中的结束事务号+1,小端存储,转换为10进制为3,实际的间隔结束事务号为2
05 00 00 00 00 00 00 00 //start:事务号间隔中的起始事务号,小端存储,转换为10进制为5
08 00 00 00 00 00 00 00 //end:事务号间隔中的结束事务号+1,小端存储,转换为10进制为8,实际的间隔结束事务号为7
78 24 a9 94 //checksum

Anonymous_gtid_log_event

MySQLbinlog中记录每一个匿名事务之前会记录一个Anonymous_gtid_log_event表示接下来的事务是一个匿名事务。

注意:因为在5.6.34中并不会产生Anonymous_gtid_log_event,所以以下内容是基于5.7.19版本解析

fixed part (post-header) 部分

字段       

字节数

描述

gtid_flags

1字节

记录binlog格式,如果gtid_flags值为1,表示binlog中可能有以statement方式记录的binlog,如果为0表示,binlog中只有以row格式记录的binlog

sid

16字节

记录GTIDuuid的部分(不记录‘-’),每1个字节表示uuid2个字符

gno

8字节

GTID中的事务号部分

logical_timestamp_typecode

1字节

判断是否有last_commitsequence_no,在logical_tmiestamp_typecode=2的情况下,有last_commitsequence_no

last_commit

8字节

上次提交的事务号

sequence_no

8字节

本次提交的序列号

 

Variable part (event-body)部分

字段       

字节数   

描述

checksum        4

4字节

校验码

字节解析示例
使用mysqlbinlog工具解析binlog文件

#180109 10:53:54 server id 9999  end_log_pos 5681 CRC32 0x46be0639    Anonymous_GTID    last_committed=20    sequence_number=21    rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 5681

解析二进制文件:

公共头部部分省略。。。
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 //sid:
00 00 00 00 00 00 00 00 //gno:
02 //logical_timestamp_typecode:判断是否有last_commit和sequence_no,在logical_tmiestamp_typecode=2的情况下,有last_commit和sequence_no,所以这边的话,后续有last_commit和sequence_no部分的内容
14 00 00 00 00 00 00 00 //last_commit:上次提交的事务号,小端存储,转换为10机制为20
15 00 00 00 00 00 00 00 //sequence_no:本次提交的序列号,小端存储,转换为10进制为21
39 06 be 46 //checksum:校验码

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。