深入MySQL(二)—— 深入理解binlog event 与解析原理
时间:05-14来源:作者:点击数:
概述
从上一篇《深入MySQL(一)—— 深入理解binlog》,我们可以知道 ——
event结构
一个binary log文件,开头是一个4byte的魔数0xfe 0x62 0x69 0x6e = “þbin”,紧随其后是各种各样的events,所有events都有一个通用结构,该结构由event header和event data组成:
+===================+
| event header |
+===================+
| event data |
+===================+
由于binlog version 一直在变化,所以event header 与 data 部分的细节也在变化,目前支持三个版本:
- v1: Used in MySQL 3.23
- v3: Used in MySQL 4.0.2 though 4.1
- v4: Used in MySQL 5.0 and up
另外需要注意三点:
- 事件结构的某些细节在所有versions中是不变的, 其他取决于版本。
- 在任何给定版本中,不同类型的事件在event data部分的结构中都不同。
- 除first event外,event data由fixed part与variable part两部分组成,
fixed part由event type决定,variable part取决于event记录的内容。
+=====================================+
| event | fixed part x : y |
| data +----------------------------+
| | variable part |
+=====================================+
first event
binlog文件中的第一个event是特别的,它包括
START_EVENT_V3和FORMAT_DESCRIPTION_EVENT两种event,又统称为descriptor event(描述符事件),它被用来决定binlog的格式version,从而采用合适的方式去读取和解释随后的events。
关于descriptor event有几个重要的点
- v1 header 的字段在v3、v4中都存在,v3、v4只是多了 next_position(下一个event的开始位置)和 flags(一个特殊标记)
- v3和v4具有相同的header字段,但data部分是不同的
- v1 header长度是13,v3和v4是19
尽管所有版本的descriptor event的data部分都包含binlog_version字段,但是我们却不能直接用它来决定binlog 的版本,因为v1 和 v3/v4 的 header 长度不同,在不知道binlog版本的情况下,我们不能定位得到binlog_version的值。
所以我们使用descriptor eventheader 部分type code和event length两个字段的值来判断 binlog的版本:
- 如果type_code不等于1(START_EVENT_V3)或 15(FORMAT_DESCRIPTION_EVENT)则版本为v3
- 如果type_code等于1(START_EVENT_V3),检查event_length,如果event_length< 75 那么是v1,否则是v3
- 如果type_code等于15(FORMAT_DESCRIPTION_EVENT),那版本是v4
需要注意的是,在MySQL的历史版本中还存在一些特殊情况,具体可以参考链接:
Row-Based下的特定events
当binlog 的格式是Row-Based时,events用来描述个别rows的数据改变。binlog中会包含几个特定类型的event:
- TABLE_MAP_EVENT
出现在所有row操作event之前,它把表的定义映射成二进制数字,表的定义包括数据库、表名和列。它的目的是当主从server之间表的定义不同时用来同步。相同事务中的row操作事件会被分组,每组事件的开头都是一组TABLE_MAP_EVENT事件,分别对应着事务中涉及的表的表定义。
- WRITE_ROWS_EVENT
包含一行数据,描述了被插入的行镜像。
- DELETE_ROWS_EVENT
包含一行数据,描述了被删除的行镜像。
- UPDATE_ROWS_EVENT
包含两行数据,第一行是被删除的行镜像,第二行是被插入的行镜像。
event约定
我们常说 “约定大于配置”,个人认为,
- 普通编程就是 —— 由人制定约定,让程序按约定自动执行。
- 深度学习就是 —— 由数据决定合适的约定,再让程序按照这个合适的约定自动执行。人所做的就是调参或改变激活函数,进行约定干预。
events内容在写入binlog文件时也同样需要遵照一些约定(否则这个过程将变得不可逆,写入的内容不可读):
- 除非另有说明,数字将按照小端序(Little-Endian,最低有效字节优先写入)写入。
- 表示位置或长度的值都认为是无符号的
- 某些数字被写成Packed整数 —— 一种有效表示无符号整数的特殊格式。 Packed整数最多可以存储8个字节的整数,而且仍然可以使用1个,3个或4个字节。 根据下表,第一个字节的值约定了如何读取数字。
First Byte |
Format |
0-250 |
只占用一个字节,这个字节的值即为数字的值 |
252 |
额外占用2个字节,数值范围:251~0xffff |
253 |
额外占用3个字节,数值范围:0xffff~0xffffff |
254 |
额外占用8个字节,数值范围:0xffffff~0xfffffffffffffff |
- 字符串支持多种格式
- 定长字符串+0x00对齐
- 可以是变长字符串,字符串前有一个描述其长度的长度字段。
- 某些变长字符串以0x00结尾,某些则不是。单个字符串字段的描述指出了哪种情况。
- 对于以0x00结尾但前面又拥有长度字段,除非另有说明,否则这个长度不包含0x00字节。
- 如果在event结尾存在变长字段,又没有长度字段来指明,那么使用e v e n t _ l e n g t h − ∑ 1 ≤ i ≤ n f i e l d _ l e n g t h i event\_length - \sum_{\mathclap{1\le i\le n}} field\_length_{i}event_length−1≤i≤n∑field_lengthi来计算。
解析binlog
通过两篇文章的学习,已经掌握了:
- binglog的format
- 如何确定binglog的version
- event结构
- event类型
- event内容约定
只需要参照以下内容即可完成binlog的解析:
- ASCII码表:https://zh.wikipedia.org/wiki/ASCII
- 不同类型Event Data详情:https://dev.mysql.com/doc/internals/en/event-data-for-specific-event-types.html
- 加载binlog文件中Events示例:https://dev.mysql.com/doc/internals/en/load-data-infile-events.html
如果还是觉得有难度,可能需要复习一下《计算机结构》
binlog Java解析工具
当然了,我们还可以站在巨人的肩膀上,
这里需要注意的是,在抽象过程中,有时候针对业务情况,Class中可能还需要抽象出特殊字段。