MySQL通过Binlog进行主从数据的复制,Binlog是一种二进制格式的文件,理解Binlog二进制格式能够帮助我们进一步理解MySQL的主从复制原理。本文将对Binlog文件格式进行分析。

本文涉及的源码版本和相关参数如下:

MySQL Server 5.7.19

binlog_format:ROW

binlog_row_image:FULL

一、Binlog文件Magic Number:

Binlog文件,前4个字节固定为一个Magic Number,十六进制值为fe62696e,如果一个文件其前4个字节不是这个Magic Number,那么就可以认为其不是一个有效的Binlog文件。

二、Binlog event:

Binlog文件除了最前面的4个字节之外,就是一个一个的event,event包含两个部分,event header和event data。通常event header大小固定,event data大小可变。

event整体结构如下:

+===================+
| event header |
+===================+
| event data  |
+===================+

event header 和 event data 详细结构如下:

| ** event header ** |
| timestamp 0 : 4 |
| 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 data **|
| fixed part x : y |
| variable part |

event header 结构解析:

timestamp:时间戳,表示该event的生成时间,占用4个字节

type_code:event类型,占用1个字节

server_id:生成event的server_id,占用4个字节

event_length:event的大小,占用4个字节

next_position:下一个event的位置,占用4个字节

flags:event flags,占用2个字节

extra_headers:额外的信息,占用的字节不确定,也可能没有。由event type为FORMAT_DESCRIPTION_EVENT 类型的event中的数据决定。

event data结构解析:

fixed part:固定的部分,每一种类型的event,其fixed part部分占用的大小是固定的。具体大小由类型为 FORMAT_DESCRIPTION_EVENT 的event中的可变数组的值决定。

variable part:可变的部分,这部分大小可变,具体由 event header 中的event_length 减去 event header 的大小 和 fixed part 部分的大小 获得。

三、FORMAT_DESCRIPTION_EVENT:

前面提到类型为FORMAT_DESCRIPTION_EVENT的event,这个event比较特殊,通常一个Binlog文件只有一个该类型的event,并且是Binlog文件中出现的第一个event。这个event存储着非常关键的元数据。

FORMAT_DESCRIPTION_EVENT类型的event,其event header固定为19个字节,没有extra_headers部分。其event data部分,只包含fixed part, 没有variable part部分。

fixed part部分如下:

binlog 版本信息:占用2个字节

mysql server 版本信息:占用50个字节

timestamp 时间戳:占用4个字节

header length:event header长度,占用1个字节,如果为19,表示所有类型的event,其event header的extra_headers部分都为空。

可变的数组,每个元素占用一个字节,数组大小与event类型数量相同,每个元素表示该类型的event data 固定部分(fixed part)占用的大小。

通过FORMAT_DESCRIPTION_EVENT event中的header length和可变的数组,就可以确定每个类型的event header大小和fixed part部分的大小。从而为解析每个类型的event打下了基础。

四、event 类型汇总:

分析源码文件 libbinlogevents/include/binlog_event.h 中的枚举类型 Log_event_type,获取所有的event类型如下,一共40个,并不是所有的类型都会使用,有一些只是兼容之前的版本。

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,
TRANSACTION_CONTEXT_EVENT= 36,
VIEW_CHANGE_EVENT= 37,
XA_PREPARE_LOG_EVENT= 38,
ENUM_END_EVENT

基本上每种类型的event,其格式各不相同,必须针对每一种类型的event进行解析,MySQL源码中也是不同的event都有其对应的c++类进行解析。