深入MySQL(二)—— 深入理解binlog event 与解析原理

1,127 阅读2分钟

概述


从上一篇《深入MySQL(一)—— 深入理解binlog》,我们可以知道 ——

  • events 是 binlog的核心, 描述了那些能够用来再现服务状态改变的行为。
  • binlog包含各种各样的events,至于每种event究竟各自描述了什么,可以参考链接:dev.mysql.com/doc/interna…

event结构


一个binary log文件,开头是一个4byte的魔数 0xfe 0x62 0x69 0x6e = “þbin” ,紧随其后是各种各样的events,所有events都有一个通用结构,该结构由 event headerevent 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

另外需要注意三点:

  1. 事件结构的某些细节在所有versions中是不变的, 其他取决于版本。
  2. 在任何给定版本中,不同类型的事件在 event data 部分的结构中都不同。
  3. first event 外,event datafixed partvariable part 两部分组成, fixed partevent type 决定, variable part 取决于event记录的内容。
     +=====================================+
     | event  | fixed part        x : y    |
     | data   +----------------------------+
     |        | variable part              |
     +=====================================+
    

first event


binlog文件中的第一个event是特别的,它包括 START_EVENT_V3FORMAT_DESCRIPTION_EVENT 两种event,又统称为 descriptor event (描述符事件),它被用来决定binlog的格式version,从而采用合适的方式去 读取解释 随后的events。

关于 descriptor event 有几个重要的点

  1. v1 header 的字段在v3、v4中都存在,v3、v4只是多了 next_position(下一个event的开始位置)和 flags(一个特殊标记)
  2. v3和v4具有相同的header字段,但data部分是不同的
  3. v1 header长度是13,v3和v4是19

尽管所有版本的 descriptor eventdata 部分都包含 binlog_version 字段,但是我们却不能直接用它来决定binlog 的版本,因为v1 和 v3/v4 的 header 长度不同,在不知道binlog版本的情况下,我们不能定位得到 binlog_version 的值。

所以我们使用 descriptor event header 部分 type codeevent length 两个字段的值来判断 binlog的版本:

  1. 如果 type_code 不等于1(START_EVENT_V3)或 15(FORMAT_DESCRIPTION_EVENT)则版本为v3
  2. 如果 type_code 等于1(START_EVENT_V3),检查 event_length ,如果event_length < 75 那么是v1,否则是v3
  3. 如果 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文件时也同样需要遵照一些约定(否则这个过程将变得不可逆,写入的内容不可读):

  1. 除非另有说明,数字将按照 小端序 (Little-Endian,最低有效字节优先写入)写入。
  2. 表示位置或长度的值都认为是无符号的
  3. 某些数字被写成Packed整数 —— 一种有效表示无符号整数的特殊格式。 Packed整数最多可以存储8个字节的整数,而且仍然可以使用1个,3个或4个字节。 根据下表,第一个字节的值约定了如何读取数字。
First ByteFormat
0-250只占用一个字节,这个字节的值即为数字的值
252额外占用2个字节,数值范围:251~0xffff
253额外占用3个字节,数值范围:0xffff~0xffffff
254额外占用8个字节,数值范围:0xffffff~0xfffffffffffffff
  1. 字符串支持多种格式
    • 定长字符串+0x00对齐
    • 可以是变长字符串,字符串前有一个描述其长度的长度字段。
    • 某些变长字符串以0x00结尾,某些则不是。单个字符串字段的描述指出了哪种情况。
    • 对于以0x00结尾但前面又拥有长度字段,除非另有说明,否则这个长度不包含0x00字节。
    • 如果在event结尾存在变长字段,又没有长度字段来指明,那么使用 event_length1infield_lengthievent\_length - \sum_{\mathclap{1\le i\le n}} field\_length_{i} 来计算。

解析binlog


通过两篇文章的学习,已经掌握了:

  • binglog的format
  • 如何确定binglog的version
  • event结构
  • event类型
  • event内容约定

只需要参照以下内容即可完成binlog的解析:

  1. ASCII码表: zh.wikipedia.org/wiki/ASCII
  2. 不同类型Event Data详情: dev.mysql.com/doc/interna…
  3. 加载binlog文件中Events示例:dev.mysql.com/doc/interna…

如果还是觉得有难度,可能需要复习一下《计算机结构》

binlog Java解析工具


当然了,我们还可以站在巨人的肩膀上,

这里需要注意的是,在抽象过程中,有时候针对业务情况,Class中可能还需要抽象出特殊字段。

关注作者公众号,随时了解更多干货!


在这里插入图片描述

往期推荐