searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

BINLOG EVENT

2024-11-08 09:21:24
1
0

binlog简介

binlog是二进制日志文件,用于记录mysql的数据更新或者潜在更新(比如DELETE语句执行删除而实际并没有符合条件的数据),在mysql主从复制中就是依靠的binlog。

需要注意下innodb引擎中的redo/undo log与mysql binlog是完全不同的日志,它们主要有以下几个区别:

  • a)层次不同。redo/undo log是innodb层维护的,而binlog是mysql server层维护的,跟采用何种引擎没有关系,记录的是所有引擎的更新操作的日志记录。innodb的redo/undo log更详细的说明可以参见姜承尧的《mysql技术内幕-innodb存储引擎》一书中相关章节。

  • b)记录内容不同。redo/undo日志记录的是每个页的修改情况,属于物理日志+逻辑日志结合的方式(redo log物理到页,页内采用逻辑日志,undo log采用的是逻辑日志),目的是保证数据的一致性。binlog记录的都是事务操作内容,比如一条语句DELETE FROM TABLE WHERE i > 1之类的,不管采用的是什么引擎,当然格式是二进制的,要解析日志内容可以用这个命令mysqlbinlog -vv BINLOG

  • c)记录时机不同。redo/undo日志在事务执行过程中会不断的写入;binlog是在事务最终commit前写入的。当然,binlog什么时候刷新到磁盘跟参数sync_binlog相关。

event结构

binlog格式分为statement,row以及mixed三种,mysql5.5默认的还是statement模式,当然我们在主从同步中一般是不建议用statement模式的,因为会有些语句不支持,比如语句中包含UUID函数,以及LOAD DATA IN FILE语句等,一般推荐的是mixed格式。暂且不管这三种格式的区别,看看binlog的存储格式是什么样的。binlog是一个二进制文件集合,当然除了我们看到的mysql-bin.xxxxxx这些binlog文件外,还有个binlog索引文件mysql-bin.index。如官方文档中所写,binlog格式如下:

  • binlog文件以一个值为0Xfe62696e的魔数开头,这个魔数对应0xfe 'b''i''n'。

  • binlog由一系列的binlog event构成。每个binlog event包含header和data两部分。

    • header部分提供的是event的公共的类型信息,包括event的创建时间,服务器等等。

    • data部分提供的是针对该event的具体信息,如具体数据的修改。

  • 从mysql5.0版本开始,binlog采用的是v4版本,第一个event都是format_desc event 用于描述binlog文件的格式版本,这个格式就是event写入binlog文件的格式。

  • 接下来的event就是按照上面的格式版本写入的event。

  • 最后一个rotate event用于说明下一个binlog文件。

  • binlog索引文件是一个文本文件,其中内容为当前的binlog文件列表。比如下面就是一个mysql-bin.index文件的内容。

/var/log/mysql/mysql-bin.000019
/var/log/mysql/mysql-bin.000020
/var/log/mysql/mysql-bin.000021

接下来分析下几种常见的event,其他的event类型可以参见官方文档。event数据结构如下:

+=====================================+
| event | timestamp         0 : 4   |
| header +----------------------------+
|       | type_code         4 : 1   |
|       +----------------------------+
|       | server_id         5 : 4   |
|       +----------------------------+
|       | event_length     9 : 4   |
|       +----------------------------+
|       | next_position   13 : 4   |
|       +----------------------------+
|       | flags           17 : 2   |
|       +----------------------------+
|       | extra_headers   19 : x-19 |
+=====================================+
| event | fixed part       x : y   |
| data   +----------------------------+
|       | variable part             |
+=====================================+

在mysql中创建一个表,依次执行插入、删除、更新操作

mysql> show create table test.t\G
*************************** 1. row ***************************
      Table: t
Create Table: CREATE TABLE `t` (
 `a` int(11) DEFAULT NULL,
 `b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)


mysql> insert into test.t values(2,5),(3,6);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0  Warnings: 0

mysql> delete from test.t where a=2;
Query OK, 1 row affected (0.00 sec)

mysql> update test.t set a=4 where b=6;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

image-20201218171741003

使用hexdump来查看各event的结构

Format_desc event

# Format_desc 偏移4,长度120
[teledb@k8s-master data8841]$ hexdump -s 4 -n $((124 - 4)) -C mysql-bin.000010
00000004 6f 72 dc 5f 0f 09 a2 69  05 78 00 00 00 7c 00 00 |or._...i.x...|..|
00000014  00 01 00 04 00 38 2e 30 2e 31 38 00 00 00 00 00 |.....8.0.18.....|
00000024  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |................|
*
00000044  00 00 00 00 00 00 00 00  00 00 00 13 00 0d 00 08 |................|
00000054  00 00 00 00 04 00 04 00  00 00 60 00 04 1a 08 00 |..........`.....|
00000064  00 00 08 08 08 02 00 00  00 0a 0a 0a 2a 2a 00 12 |............**..|
00000074  34 00 0a 01 a7 33 f4 59                           |4....3.Y|
0000007c

先看前19个字节的event头部,

前4个字节是时间戳;

0f表示event类型,对应FORMAT_DESCRIPTION_EVENT=15;

紧接着的09 a2 69 05是server_id,对应程序中配置的十进制数90808841(0x0569a209,x86架构是小端序);

之后的4个字节是event长度,00 00 00 78表示该event长度为120;

再然后是下一个event起始点,00 00 00 7c表示下一个event起始点为124;

接着的2个字节的00 01是flag(1为LOG_EVENT_BINLOG_IN_USE_F,标识binlog还没有关闭,binlog关闭后,flag会被设置为0。

到此公共头的部分就结束了。

image-20201218173902732

然后是这个event的data部分,event的data分为Fixed dataVariable data两部分,其中Fixed data是event的固定长度和格式的数据,Variable data则是长度变化的数据,比如format_desc event的Fixed data长度是0x60=96个字节。下面看下这96=2+50+4+1+39个字节的分配:开始的2个字节0x0004为binlog的版本号4,接着的50个字节为mysql-server版本,该binlog显示是8.0.18,与SELECT version();查看的结果一致。接下来4个字节是binlog创建时间,这里是0;然后的1个字节0x13是指之后所有event的公共头长度,这里都是19;接着的39个字节中每个字节为mysql已知的event(共39个)的Fixed data的长度;可以发现format_desc event自身的Variable data部分为5。

image-20201222093216383

type_code为15的Format_desc event的fix data长度为0x60(96)

image-20201222193223441

Query event

[teledb@k8s-master data8841]$ hexdump -s 274 -n $((345 - 274)) -C mysql-bin.000010
00000112  01 73 dc 5f 02 09 a2 69  05 47 00 00 00 59 01 00 |.s._...i.G...Y..|
00000122  00 08 00|5e|00 00 00 00 |00 00 00 00|00 00|1d 00| |...^............|
00000132  00 00 00 00 00 01 00 00 a0 45 00 00 00 00 06 03 |.........E......|
00000142  73 74 64 04 ff 00 ff 00 2e 00 12|ff 00 00|42 45 |std...........BE|
00000152  47 49 4e 72 c1 2b e0                             |GINr.+.|
00000159

头部跟之前的event一样,只是query event的type为0x02,长度为0x47=71,下一个event位置为0x 01 59 = 345。flag为8,接着是data部分,从format_desc event我们可以知道query event的Fixed data部分为13个字节,因此也可以算出Variable data部分为71-19-13=39字节。

  • Fixed data:首先的4个字节0x 00 00 00 5e为执行该语句的thread id,接下来的4个字节是执行的时间0(以秒为单位),接下来的1个字节0x04是语句执行时的默认数据库名字的长度(这里没有指定默认数据库)。接着的2个字节0x0000是错误码(注:通常情况下错误码是0表示没有错误,但是在一些非事务性表如myisam表执行INSERT...SELECT语句时可能插入部分数据后遇到duplicate-key错误会产生错误码1062,或者是事务性表在INSERT...SELECT出错不会插入部分数据,但是在执行过程中CTRL+C终止语句也可能记录错误码。slave db在复制时会执行后检查错误码是否一致,如果不一致,则复制过程会中止),接着2个字节0x001d为状态变量块的长度29。

  • Variable data:从0x001d之后的29个字节为状态变量块,然后是默认数据库名,以0x00结尾,然后是sql语句BEGIN,最后4个字节是校验码。

Rows_query event

[teledb@k8s-master data8841]$ hexdump -s 345 -n $((405 - 345)) -C mysql-bin.000010
00000159  01 73 dc 5f 1d 09 a2 69  05 3c 00 00 00 95 01 00 |.s._...i.<......|
00000169  00 80 00 24 69 6e 73 65  72 74 20 69 6e 74 6f 20 |...$insert into |
00000179  74 65 73 74 2e 74 20 76  61 6c 75 65 73 28 32 2c |test.t values(2,|
00000189  35 29 2c 28 33 2c 36 29 6a c1 02 50             |5),(3,6)j..P|
00000195

该种类型的event比较简单,type是0x1d,除了公共头和最后的校验码以外 ,中间的就是执行的sql语句。

Table_map event

一、介绍

TABLE_MAP_EVENT用于描述即将发生变化的表的结构。ROW模式下,当用户提交一条修改语句时(如, insert, update, delete),MySQL会产生2个Binlog事件: 第一个就是TABLE_MAP_EVENT,用于描述改变对应表的结构(表名, 列的数据类型等信息);紧接着的是ROWS_EVENT,用于描述对应表的行的变化值

table_map_event对应的class是Table_map_log_event(对应源码sql/log_event.cc)

二、格式

table_map_log_event的格式如下图所示:

image-20211028200057043

- pack_length

首先介绍一个常用的术语pack_length。它是一种数值的存储方式,在Binary Log和MySQL的通讯包中经常用到。为了减少存储和传输时占用的空间,长度字段和整形的数值采用变长的方式存储。具体算法是:

- 小于251的数值

用1个字节直接存储该数值

- 大于等于251,小于等于65535(0xFF)的数值

先用1个字节存储数值252,再用2个字节存储该数值。

- 大于65535,小于等于16777215(0xFFF)的数值

先用1个字节存储数值253,再用3个字节存储该数值。

- 大于16777215的数值

先用1个字节存储数值254,再用8个字节存储该数值。

如果大多数情况下,数值小于251,这种存储方法比较节约空间。同时,又能够支持数值很大的情况。

- 参考代码

sql-common/pack.c中的net_store_length().

- Event Header

和其他 event一样。

- table id

table id就像一个表的主键,唯一识别一个table_map_log_event。为了节省空间,rows event中不会记录数据库名和表名,只会记录一个table id。通过table id来关联到一个table_map_log_event,就可以知道是哪个表产生的。

- flags

目前未使用,内容始终为0,占2字节。

- db name length

数据库名的长度,不包含'\0'。采用pack_lenght存储。

- database name

数据库名,以'\0'结尾,因此占用的空间是db name length+1字节。

- table name length

表名长度,不包含'\0'。采用pack_lenght存储。

- table name

表名名,以'\0'结尾,因此占用的空间是table name length+1字节。

- column count 字段的个数。采用pack_lenght存储。

- column types

这里的字段类型不是SQL语句中的类型而是MySQL内部的数据类型。每个字段的类型占一个字节,总长度等于字段的个数(column count)。类型存储的顺序是按照master上该表中字段的顺序产生的。所以如果slave上表的字段顺序变了,就会导致错误。

- metadata length

字段的元数据长度。采用pack_lenght存储。

- metadata

除了类型,字段还有长度等属性。这些属性信息存储在metadata中,后边会详细介绍。

- null flags

字段是否可以为空的属性,通过位图方式记录,1个bit记录一个字段。

 

[teledb@k8s-master data8841]$ hexdump -s 405 -n $((453 - 405)) -C mysql-bin.000010
00000195  01 73 dc 5f 13 09 a2 69  05 30 00 00 00 c5 01 00 |.s._...i.0......|
000001a5  00 00 00|60 00 00 00 00  00|01 00|04|74 65 73 74 |...`........test|
000001b5  00|01|74 00|02|03 03|00| 03 01 01 00|fb 05 bf 96 |..t.............|
000001c5

type: 0x13,公共头之后fix data部分长度为8,前6个字节0x 00 00 00 00 00 60是table id,然后的2个字节0x 00 01是flag。Variable data部分,首先1个字节0x04为数据库名test的长度,然后5个字节是数据库名test + \0。接着1个字节0x01为表名长度,接着2个字节为表名t + \0。接着1个字节0x02为列的数目。而后是2个列的类型定义,此处都是0x03(列的类型MYSQL_TYPE_LONG为0x03)。接着是列的元数据定义,0x00表示元数据长度为0,因为MYSQL_TYPE_LONG没有元数据。然后是metadata和null flag信息,以及校验码。

 

Write_rows event

[teledb@k8s-master data8841]$ hexdump -s 453 -n $((506 - 453)) -C mysql-bin.000010
000001c5  01 73 dc 5f 1e 09 a2 69  05 35 00 00 00 fa 01 00 |.s._...i.5......|
000001d5  00 00 00|60 00 00 00 00  00|01 00|02 00|02|ff|00| |...`............|
000001e5  02 00 00 00|05 00 00 00| 00|03 00 00 00|06 00 00 |................|
000001f5  00|59 59 8f 73                                   |.YY.s|
000001fa

type: 0x1e,公共头之后的6个字节0x 00 00 00 00 00 60是table id,然后的2个字节0x 00 01是flag,接着的2个字节0x 00 02 是extra_data_len(extra_data_len - 2是extra_data的长度,此处为空)接着的1个字节0x 02表示列的数量,然后1个字节0xff各个bit标识各列是否存在值,这里表示都存在?。

接着的就是插入的各行数据了,第1个字节0x00的各个bit标识该行变化之后各列是否为NULL,为NULL的bit记为0,(00表示全部非null),MYSQL_TYPE_LONG长度为4个字节,故可以看出受到影响的列为(0x 00 00 00 02,0x 00 00 00 05),(0x 00 00 00 03,0x 00 00 00 06),也就是插入的值。

 

Delete_rows event

[teledb@k8s-master data8841]$ hexdump -s 787 -n $((831 - 787)) -C mysql-bin.000010
00000313  48 73 dc 5f 20 09 a2 69  05 2c 00 00 00 3f 03 00 |Hs._ ..i.,...?..|
00000323  00 00 00 60 00 00 00 00  00 01 00 02 00 02 ff 00 |...`............|
00000333  02 00 00 00 05 00 00 00  58 7c a8 9f             |........X|..|
0000033f

type: 0x20,分析基本和Write_rows event一致,只是event类型变了。

Update_rows event

[teledb@k8s-master data8841]$ hexdump -s 1124 -n $((1178 - 1124)) -C mysql-bin.000010
00000464 5e 73 dc 5f 1f 09 a2 69 05 36 00 00 00 9a 04 00 |^s._...i.6......|
00000474 00 00 00|60 00 00 00 00 00|01 00|02 00|02|ff|ff| |...`............|
00000484 00|03 00 00 00|06 00 00 00|00|04 00 00 00|06 00 |................|
00000494 00 00|56 f2 7f e4                                 |..V...|
0000049a

type: 0x1f,受到影响的列为(0x 00 00 00 03,0x 00 00 00 06),变为(0x 00 00 00 04,0x 00 00 00 06)

Xid event

[teledb@k8s-master data8841]$ hexdump -s 506 -n $((537 - 506)) -C mysql-bin.000010
000001fa  01 73 dc 5f 10 09 a2 69  05 1f 00 00 00 19 02 00 |.s._...i........|
0000020a  00 00 00 85 98 0a 00 00  00 00 00 84 01 6f 55     |.............oU|
00000219

xid event为COMMIT语句。前19个字节是通用头部,type是0x10(16)。data部分中Fixed data为空,而variable data为8个字节,这8个字节0x85 98 0a 00 00 00 00 00是事务编号,最后4个字节 为校验码。

 

0条评论
作者已关闭评论
廖****兴
5文章数
0粉丝数
廖****兴
5 文章 | 0 粉丝
廖****兴
5文章数
0粉丝数
廖****兴
5 文章 | 0 粉丝
原创

BINLOG EVENT

2024-11-08 09:21:24
1
0

binlog简介

binlog是二进制日志文件,用于记录mysql的数据更新或者潜在更新(比如DELETE语句执行删除而实际并没有符合条件的数据),在mysql主从复制中就是依靠的binlog。

需要注意下innodb引擎中的redo/undo log与mysql binlog是完全不同的日志,它们主要有以下几个区别:

  • a)层次不同。redo/undo log是innodb层维护的,而binlog是mysql server层维护的,跟采用何种引擎没有关系,记录的是所有引擎的更新操作的日志记录。innodb的redo/undo log更详细的说明可以参见姜承尧的《mysql技术内幕-innodb存储引擎》一书中相关章节。

  • b)记录内容不同。redo/undo日志记录的是每个页的修改情况,属于物理日志+逻辑日志结合的方式(redo log物理到页,页内采用逻辑日志,undo log采用的是逻辑日志),目的是保证数据的一致性。binlog记录的都是事务操作内容,比如一条语句DELETE FROM TABLE WHERE i > 1之类的,不管采用的是什么引擎,当然格式是二进制的,要解析日志内容可以用这个命令mysqlbinlog -vv BINLOG

  • c)记录时机不同。redo/undo日志在事务执行过程中会不断的写入;binlog是在事务最终commit前写入的。当然,binlog什么时候刷新到磁盘跟参数sync_binlog相关。

event结构

binlog格式分为statement,row以及mixed三种,mysql5.5默认的还是statement模式,当然我们在主从同步中一般是不建议用statement模式的,因为会有些语句不支持,比如语句中包含UUID函数,以及LOAD DATA IN FILE语句等,一般推荐的是mixed格式。暂且不管这三种格式的区别,看看binlog的存储格式是什么样的。binlog是一个二进制文件集合,当然除了我们看到的mysql-bin.xxxxxx这些binlog文件外,还有个binlog索引文件mysql-bin.index。如官方文档中所写,binlog格式如下:

  • binlog文件以一个值为0Xfe62696e的魔数开头,这个魔数对应0xfe 'b''i''n'。

  • binlog由一系列的binlog event构成。每个binlog event包含header和data两部分。

    • header部分提供的是event的公共的类型信息,包括event的创建时间,服务器等等。

    • data部分提供的是针对该event的具体信息,如具体数据的修改。

  • 从mysql5.0版本开始,binlog采用的是v4版本,第一个event都是format_desc event 用于描述binlog文件的格式版本,这个格式就是event写入binlog文件的格式。

  • 接下来的event就是按照上面的格式版本写入的event。

  • 最后一个rotate event用于说明下一个binlog文件。

  • binlog索引文件是一个文本文件,其中内容为当前的binlog文件列表。比如下面就是一个mysql-bin.index文件的内容。

/var/log/mysql/mysql-bin.000019
/var/log/mysql/mysql-bin.000020
/var/log/mysql/mysql-bin.000021

接下来分析下几种常见的event,其他的event类型可以参见官方文档。event数据结构如下:

+=====================================+
| event | timestamp         0 : 4   |
| header +----------------------------+
|       | type_code         4 : 1   |
|       +----------------------------+
|       | server_id         5 : 4   |
|       +----------------------------+
|       | event_length     9 : 4   |
|       +----------------------------+
|       | next_position   13 : 4   |
|       +----------------------------+
|       | flags           17 : 2   |
|       +----------------------------+
|       | extra_headers   19 : x-19 |
+=====================================+
| event | fixed part       x : y   |
| data   +----------------------------+
|       | variable part             |
+=====================================+

在mysql中创建一个表,依次执行插入、删除、更新操作

mysql> show create table test.t\G
*************************** 1. row ***************************
      Table: t
Create Table: CREATE TABLE `t` (
 `a` int(11) DEFAULT NULL,
 `b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)


mysql> insert into test.t values(2,5),(3,6);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0  Warnings: 0

mysql> delete from test.t where a=2;
Query OK, 1 row affected (0.00 sec)

mysql> update test.t set a=4 where b=6;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

image-20201218171741003

使用hexdump来查看各event的结构

Format_desc event

# Format_desc 偏移4,长度120
[teledb@k8s-master data8841]$ hexdump -s 4 -n $((124 - 4)) -C mysql-bin.000010
00000004 6f 72 dc 5f 0f 09 a2 69  05 78 00 00 00 7c 00 00 |or._...i.x...|..|
00000014  00 01 00 04 00 38 2e 30 2e 31 38 00 00 00 00 00 |.....8.0.18.....|
00000024  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |................|
*
00000044  00 00 00 00 00 00 00 00  00 00 00 13 00 0d 00 08 |................|
00000054  00 00 00 00 04 00 04 00  00 00 60 00 04 1a 08 00 |..........`.....|
00000064  00 00 08 08 08 02 00 00  00 0a 0a 0a 2a 2a 00 12 |............**..|
00000074  34 00 0a 01 a7 33 f4 59                           |4....3.Y|
0000007c

先看前19个字节的event头部,

前4个字节是时间戳;

0f表示event类型,对应FORMAT_DESCRIPTION_EVENT=15;

紧接着的09 a2 69 05是server_id,对应程序中配置的十进制数90808841(0x0569a209,x86架构是小端序);

之后的4个字节是event长度,00 00 00 78表示该event长度为120;

再然后是下一个event起始点,00 00 00 7c表示下一个event起始点为124;

接着的2个字节的00 01是flag(1为LOG_EVENT_BINLOG_IN_USE_F,标识binlog还没有关闭,binlog关闭后,flag会被设置为0。

到此公共头的部分就结束了。

image-20201218173902732

然后是这个event的data部分,event的data分为Fixed dataVariable data两部分,其中Fixed data是event的固定长度和格式的数据,Variable data则是长度变化的数据,比如format_desc event的Fixed data长度是0x60=96个字节。下面看下这96=2+50+4+1+39个字节的分配:开始的2个字节0x0004为binlog的版本号4,接着的50个字节为mysql-server版本,该binlog显示是8.0.18,与SELECT version();查看的结果一致。接下来4个字节是binlog创建时间,这里是0;然后的1个字节0x13是指之后所有event的公共头长度,这里都是19;接着的39个字节中每个字节为mysql已知的event(共39个)的Fixed data的长度;可以发现format_desc event自身的Variable data部分为5。

image-20201222093216383

type_code为15的Format_desc event的fix data长度为0x60(96)

image-20201222193223441

Query event

[teledb@k8s-master data8841]$ hexdump -s 274 -n $((345 - 274)) -C mysql-bin.000010
00000112  01 73 dc 5f 02 09 a2 69  05 47 00 00 00 59 01 00 |.s._...i.G...Y..|
00000122  00 08 00|5e|00 00 00 00 |00 00 00 00|00 00|1d 00| |...^............|
00000132  00 00 00 00 00 01 00 00 a0 45 00 00 00 00 06 03 |.........E......|
00000142  73 74 64 04 ff 00 ff 00 2e 00 12|ff 00 00|42 45 |std...........BE|
00000152  47 49 4e 72 c1 2b e0                             |GINr.+.|
00000159

头部跟之前的event一样,只是query event的type为0x02,长度为0x47=71,下一个event位置为0x 01 59 = 345。flag为8,接着是data部分,从format_desc event我们可以知道query event的Fixed data部分为13个字节,因此也可以算出Variable data部分为71-19-13=39字节。

  • Fixed data:首先的4个字节0x 00 00 00 5e为执行该语句的thread id,接下来的4个字节是执行的时间0(以秒为单位),接下来的1个字节0x04是语句执行时的默认数据库名字的长度(这里没有指定默认数据库)。接着的2个字节0x0000是错误码(注:通常情况下错误码是0表示没有错误,但是在一些非事务性表如myisam表执行INSERT...SELECT语句时可能插入部分数据后遇到duplicate-key错误会产生错误码1062,或者是事务性表在INSERT...SELECT出错不会插入部分数据,但是在执行过程中CTRL+C终止语句也可能记录错误码。slave db在复制时会执行后检查错误码是否一致,如果不一致,则复制过程会中止),接着2个字节0x001d为状态变量块的长度29。

  • Variable data:从0x001d之后的29个字节为状态变量块,然后是默认数据库名,以0x00结尾,然后是sql语句BEGIN,最后4个字节是校验码。

Rows_query event

[teledb@k8s-master data8841]$ hexdump -s 345 -n $((405 - 345)) -C mysql-bin.000010
00000159  01 73 dc 5f 1d 09 a2 69  05 3c 00 00 00 95 01 00 |.s._...i.<......|
00000169  00 80 00 24 69 6e 73 65  72 74 20 69 6e 74 6f 20 |...$insert into |
00000179  74 65 73 74 2e 74 20 76  61 6c 75 65 73 28 32 2c |test.t values(2,|
00000189  35 29 2c 28 33 2c 36 29 6a c1 02 50             |5),(3,6)j..P|
00000195

该种类型的event比较简单,type是0x1d,除了公共头和最后的校验码以外 ,中间的就是执行的sql语句。

Table_map event

一、介绍

TABLE_MAP_EVENT用于描述即将发生变化的表的结构。ROW模式下,当用户提交一条修改语句时(如, insert, update, delete),MySQL会产生2个Binlog事件: 第一个就是TABLE_MAP_EVENT,用于描述改变对应表的结构(表名, 列的数据类型等信息);紧接着的是ROWS_EVENT,用于描述对应表的行的变化值

table_map_event对应的class是Table_map_log_event(对应源码sql/log_event.cc)

二、格式

table_map_log_event的格式如下图所示:

image-20211028200057043

- pack_length

首先介绍一个常用的术语pack_length。它是一种数值的存储方式,在Binary Log和MySQL的通讯包中经常用到。为了减少存储和传输时占用的空间,长度字段和整形的数值采用变长的方式存储。具体算法是:

- 小于251的数值

用1个字节直接存储该数值

- 大于等于251,小于等于65535(0xFF)的数值

先用1个字节存储数值252,再用2个字节存储该数值。

- 大于65535,小于等于16777215(0xFFF)的数值

先用1个字节存储数值253,再用3个字节存储该数值。

- 大于16777215的数值

先用1个字节存储数值254,再用8个字节存储该数值。

如果大多数情况下,数值小于251,这种存储方法比较节约空间。同时,又能够支持数值很大的情况。

- 参考代码

sql-common/pack.c中的net_store_length().

- Event Header

和其他 event一样。

- table id

table id就像一个表的主键,唯一识别一个table_map_log_event。为了节省空间,rows event中不会记录数据库名和表名,只会记录一个table id。通过table id来关联到一个table_map_log_event,就可以知道是哪个表产生的。

- flags

目前未使用,内容始终为0,占2字节。

- db name length

数据库名的长度,不包含'\0'。采用pack_lenght存储。

- database name

数据库名,以'\0'结尾,因此占用的空间是db name length+1字节。

- table name length

表名长度,不包含'\0'。采用pack_lenght存储。

- table name

表名名,以'\0'结尾,因此占用的空间是table name length+1字节。

- column count 字段的个数。采用pack_lenght存储。

- column types

这里的字段类型不是SQL语句中的类型而是MySQL内部的数据类型。每个字段的类型占一个字节,总长度等于字段的个数(column count)。类型存储的顺序是按照master上该表中字段的顺序产生的。所以如果slave上表的字段顺序变了,就会导致错误。

- metadata length

字段的元数据长度。采用pack_lenght存储。

- metadata

除了类型,字段还有长度等属性。这些属性信息存储在metadata中,后边会详细介绍。

- null flags

字段是否可以为空的属性,通过位图方式记录,1个bit记录一个字段。

 

[teledb@k8s-master data8841]$ hexdump -s 405 -n $((453 - 405)) -C mysql-bin.000010
00000195  01 73 dc 5f 13 09 a2 69  05 30 00 00 00 c5 01 00 |.s._...i.0......|
000001a5  00 00 00|60 00 00 00 00  00|01 00|04|74 65 73 74 |...`........test|
000001b5  00|01|74 00|02|03 03|00| 03 01 01 00|fb 05 bf 96 |..t.............|
000001c5

type: 0x13,公共头之后fix data部分长度为8,前6个字节0x 00 00 00 00 00 60是table id,然后的2个字节0x 00 01是flag。Variable data部分,首先1个字节0x04为数据库名test的长度,然后5个字节是数据库名test + \0。接着1个字节0x01为表名长度,接着2个字节为表名t + \0。接着1个字节0x02为列的数目。而后是2个列的类型定义,此处都是0x03(列的类型MYSQL_TYPE_LONG为0x03)。接着是列的元数据定义,0x00表示元数据长度为0,因为MYSQL_TYPE_LONG没有元数据。然后是metadata和null flag信息,以及校验码。

 

Write_rows event

[teledb@k8s-master data8841]$ hexdump -s 453 -n $((506 - 453)) -C mysql-bin.000010
000001c5  01 73 dc 5f 1e 09 a2 69  05 35 00 00 00 fa 01 00 |.s._...i.5......|
000001d5  00 00 00|60 00 00 00 00  00|01 00|02 00|02|ff|00| |...`............|
000001e5  02 00 00 00|05 00 00 00| 00|03 00 00 00|06 00 00 |................|
000001f5  00|59 59 8f 73                                   |.YY.s|
000001fa

type: 0x1e,公共头之后的6个字节0x 00 00 00 00 00 60是table id,然后的2个字节0x 00 01是flag,接着的2个字节0x 00 02 是extra_data_len(extra_data_len - 2是extra_data的长度,此处为空)接着的1个字节0x 02表示列的数量,然后1个字节0xff各个bit标识各列是否存在值,这里表示都存在?。

接着的就是插入的各行数据了,第1个字节0x00的各个bit标识该行变化之后各列是否为NULL,为NULL的bit记为0,(00表示全部非null),MYSQL_TYPE_LONG长度为4个字节,故可以看出受到影响的列为(0x 00 00 00 02,0x 00 00 00 05),(0x 00 00 00 03,0x 00 00 00 06),也就是插入的值。

 

Delete_rows event

[teledb@k8s-master data8841]$ hexdump -s 787 -n $((831 - 787)) -C mysql-bin.000010
00000313  48 73 dc 5f 20 09 a2 69  05 2c 00 00 00 3f 03 00 |Hs._ ..i.,...?..|
00000323  00 00 00 60 00 00 00 00  00 01 00 02 00 02 ff 00 |...`............|
00000333  02 00 00 00 05 00 00 00  58 7c a8 9f             |........X|..|
0000033f

type: 0x20,分析基本和Write_rows event一致,只是event类型变了。

Update_rows event

[teledb@k8s-master data8841]$ hexdump -s 1124 -n $((1178 - 1124)) -C mysql-bin.000010
00000464 5e 73 dc 5f 1f 09 a2 69 05 36 00 00 00 9a 04 00 |^s._...i.6......|
00000474 00 00 00|60 00 00 00 00 00|01 00|02 00|02|ff|ff| |...`............|
00000484 00|03 00 00 00|06 00 00 00|00|04 00 00 00|06 00 |................|
00000494 00 00|56 f2 7f e4                                 |..V...|
0000049a

type: 0x1f,受到影响的列为(0x 00 00 00 03,0x 00 00 00 06),变为(0x 00 00 00 04,0x 00 00 00 06)

Xid event

[teledb@k8s-master data8841]$ hexdump -s 506 -n $((537 - 506)) -C mysql-bin.000010
000001fa  01 73 dc 5f 10 09 a2 69  05 1f 00 00 00 19 02 00 |.s._...i........|
0000020a  00 00 00 85 98 0a 00 00  00 00 00 84 01 6f 55     |.............oU|
00000219

xid event为COMMIT语句。前19个字节是通用头部,type是0x10(16)。data部分中Fixed data为空,而variable data为8个字节,这8个字节0x85 98 0a 00 00 00 00 00是事务编号,最后4个字节 为校验码。

 

文章来自个人专栏
jvm知识
5 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0