MySQL对于binlog的处理是以事件为单位的,每一次DML操作可能会产生多次事件,例如对于 innodb 存储引擎,会额外产生一条 query_event(事务的begin语句)和 xid_event(事务提交)。

那么我们如何获取到这些事件呢?

1. 发送DUMP包

首先,我们知道 MySQL 本身就带有 replication 的机制,我们需要伪造一个 slave,向 master 注册,这样的话 master 才会发送 binlog event。

注册很简单,通过调用 limysql.so 中的 cli_advanced_command(),指定 binlog filename + position,向 master 发送 COM_BINLOG_DUMP 命令。

在发送 dump 命令的时候,我们可以指定 flag 为 BINLOG_DUMP_NON_BLOCK,这样 master 在没有可以发送的 binlog event 之后,就会返回一个 EOF 的包。

数据包的具体格式如下:

例如 COM_BINLOG_DUMP 类型的数据包 payload(数据包体)是这样的:

2. 接收事件

通过调用 libmysql.so 库中的 cli_safe_read()函数,获得 master 发过来的数据,每次获得一个事件记录的数据,cli_safe_read()的返回值标示了从 master 发送过来的数据的数据字节数。

而发送过来的数据保存在 mysql->net->read_pos 数组中。

Binlog 事件

通过调用 libmysql.so 库中的 cli_safe_read()函数可以获取一次 binlog 事件。

MySQL 的 Binlog 事件类型有27种,在 MySQL 5.6之后增加到 38 种,但是我们只介绍与 ROW 模式相关的事件,所有的 event 都含有如下通用的事件结构:

+===============================+

| event header |

+===============================+

| event data |

+===============================+

分别为事件头和事件体组成,而事件的内部结构随MySQL版本的不同而变化着,我们需要用到的版本为 v4,用于 mysql5.1 及以上,其他版本就不做介绍了,想要了解的朋友可以参考官方文档。

下图为v4版本的 event header 格式。

由于各个事件的事件头一致,这里我们就不重复介绍了,后面各个事件我们也将忽略对事件头字段的描述。

ROTATE_EVENT

ROTATE_EVENT,记录了接下来要请求的 binlog 的信息。格式如下:

它里面其实就是标明下一个 event 所在的 binlog filename 和 position。

这里需要注意的是,当 slave 发送 binlog dump 之后,master会首先发送一个 ROTATE_EVENT,用来告知 slave 下一个 event 所在的位置,然后才跟着其他事件。

QUERY_EVENT

QUERY_EVENT, 存储的是SQL,主要是一些与数据无关的操作,如 begin,alter table,drop table, create table 等。格式如下

TABLE_MAP_EVENT

TABLE_MAP_EVENT,记录了某个 table 所对应的表信息,在其中存储了数据库名和表名等。格式如下:

在这个事件中我们需要注意的是,虽然我们可以用表的 id 标识符 table_id 来代表一个特定的表,但是因为 alter table 或 rotate binlog event等原因,master 会改变某个 table 的 table_id,

所以我们在外部不能使用这个 table_id 来索引某个 table。

还需要关注的就是里面的 column meta 信息,后续我们解析 ROW_EVENT 的时候会根据这个来处理不同类型的数据。

ROWS_EVENT

ROWS_EVENT,包含了 insert,update,以及 delete 三种 event ,并且有 v0,v1,v2 三个版本。

ROWS_EVENT 的基本格式如下:

在这里 MySQL5.6 开始 event 的 type 发生变化了,所以 MySQL5.6 需要改一下,

所以为了我们软件的版本兼容性,我们需要在软件中支持不同的版本。

MySQL 5.1 ~ MySQL 5.6

TABLE_MAP_EVENT: 19

WRITE_ROWS_EVENT : 23

UPDATE_ROWS_EVENT : 24

DELETE_ROWS_EVENT : 25

MySQL 5.6 以上

TABLE_MAP_EVENT: 19

WRITE_ROWS_EVENT : 30

UPDATE_ROWS_EVENT : 31

DELETE_ROWS_EVENT : 32

ROWS_EVENT 的 table_id 跟 TABLE_MAP_EVENT 一样,虽然 table_id 可能变化,但是 ROWS_EVENT 和 TABLE_MAP_EVENT 的 table_id 是能保证一致的,所以我们也是通过这个来找到 TABLE_MAP_EVENT 的。

为了节省空间,ROWS_EVENT 里面对于各列状态都是采用 bitmap 的方式来处理的。首先我们需要得到 column present bitmap 的数据,

这个值用来表示当前列的一些状态,如果没有设置,也就是某列对应的 bit 为0,表名该 ROWS_EVENT 里该列的数据,外部用 null 代替就可以了。

然后就是每个 record 里的 bitmap,这个是用来表明一行实际的数据里面有哪些列是 NULL 的,如果该列为 NULL,则为 1。

在得到 column_bitmap 和 null_bitmap 后,我们就可以实际解析这行对应的数据了,对于每一列,首先判断是否 column_bitmap 标记了,如果为 0,这跳过用 null 表示,

然后再看是否 null_bitmap 里面标记了,如果为 1,则表明为 null。

但是,因为我们得到的是一行数据的二进制流,又如何将一列数据解析出来呢,这里就需要靠 TABLE_MAP_EVENT 里的 column_meta 了。

Column_def 中定义了该列的数据类型,对于一些特定的类型,譬如 MYSQL_TYPE_LONG,MYSQL_TYPE_TINY 等,长度都是固定的,所以我们可以直接读取对应长度的数据得到实际的值,

但对于一些类型,则没有这么简单。这时候就需要通过meta来辅助计算了。

举个例子:

MYSQL_TYPE_BLOB 类型,meta为 1 表示的为 tinyblob,第一个字节解释 blob 的长度,2 表名的是 shortblob,前两个字节为 blob 的长度等,而对于 MYSQL_TYPE_VARCHAR,meta 存储的则是 string 的长度,下一小节我们介绍每一种类型的计算方法。

XID_EVENT

XID_EVENT 一般出现在一个事务操作之后或者其他语句提交之后。它的主要作用提交事务操作和把事件刷新至 binlog 文件中。里面存的是 8 个字节的事务 ID 号。

3. 不同的数据类型的长度

上一节我们介绍了在不同事件的事件格式以及需要注意的事项,在其中 ROWS_EVENT 事件中,在 record 中 bit_map 之后的列数据中,针对不同的数据类型,可能在 record 中占用不同的字节,因从需要针对每种数据类型进行处理,

下面列出大部分常用数据类型的字节数和解析方法:

MYSQL_TYPE_INT 家族

MYSQL_TYPE_DOUBLE 家族

MYSQL_TYPE_NEWDECIMAL 类型

声明语法为 decimal(M,D),decimal 参量的取值范围如下:M 为数字的最大数(精度),其范围为 1 ~ 65,默认为 10

D 是小数点后面的数目(标度)。范围为 0 ~ 30,但不得超过 M

table_map_event 中的 metadata 为 2 个字节,它会记录该类型的精度和标度,其中第一个字节表示精度,第二个字节表示精度。那么数据的长度是如何计算的呢?

比如说 decimal(15, 5) a = 1234567890.12345,那么 a 的精度为 15,标度为 5,所以 a 的整数位最多为 10,mysql 中每 9 个数字用一个 32 位 4 个字节的整形来存储,剩下不够 9 个字节的按照如下方式:

int dig2byte[10] = { 0, 1, 1, 2, 3, 3, 3, 4, 4, 4 };

该数组表示剩下几个字节的数字用几个字节存储。为什么这样做呢,我们知道一个 int 型变量能存储的最大整数位 2^32,是一个十位数的整数,所以最多可以表示9位数的数字。

binlog 中的 decimal 按照小数点前后分别存储,所以a的整数位需要2个 int 型来存储,小数后的计算方式也一样,需要3个字节存储,所以 decimal(15, 5)在 binlog 中需要 11 个字节来存储数据

MYSQL_TYPE_STRING

处理该类型数据时,需要利用 metadata 辅助计算,metadata 的前一个字节表示类型,后一个字节表示长度,如果类型为 MYSQL_TYPE_SET 和 MYSQL_TYPE_EUM 时,数据的长度则为后一个字节的大小。

如果类型为 MYSQL_TYPE_STRING,第一个字节的数字即为该类型数据的长度。

MYSQL_TYPE_BIT

MYSQL_TYPE_DATA 家族

MYSQL_TYPE_BLOB 家族

Metadata 为 1,第一个字节表示长度,metadata 为 2,前两个字节表示长度,metadata 为 3,前三个字节表示长度,metadata 为 4,前四个字节表示长度。

MYSQL_TYPE_VARCHAR

如果 metadata 小于 256,则第一个字节表示数据的长度,如果 metadata 大于 256 则前两个字节表示数据的长度。

mysql binlog rotate_mysql binlog日志存储格式相关推荐

  1. MySQL中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简单总结...

    MySQL中有六种日志文件, 分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query log). ...

  2. MySQL中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简单总结

    前言 1. ''最近公司大佬让我优化sql的时候,说可以通过控制where条件,尽可能的少的较少数据库的开支,少生成一些无用的binlog.由此引出binlog这个概念,大家一起学习一下 关于Binl ...

  3. MySQL日志:binlog、事务日志(redo、undo)

    事务的隔离性是通过锁实现,而事务的原子性.一致性和持久性则是通过日志实现.Mysql的日志可以分为: binlog:server层实现 事务日志:包括redo log.undo log,引擎层(inn ...

  4. mysql重做日志与binlog日志区别_【135期】谈谈MySQL中的重做日志,回滚日志,以及二进制日志的区别及各自作用...

    MySQL中有六种日志文件,分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query log).一 ...

  5. MySQL中的binlog日志

    binlog是mysql的日志工具,binlog日志可以记录insert.update.delete的sql和操作时间.因为log数据是二进制格式的,所以称为binary log,即binlog. 文 ...

  6. mysql日志备份的脚本_脚本备份MySQL数据库和binlog日志

    用Mysqldump实现全库备份+binlog的数据还原 首先是为mysql做指定库文件的全库备份 vim mysqlbak.sh #!/bin/bash #定义数据库目录,要能找到mysqldump ...

  7. mysql未开启binlog如何恢复数据_MySQL5.7开启binlog日志,及数据恢复简单示例

    1.相关命令 1)查看是否开启 binlog日志(默认不开启,log_bin值为OF)及日志位置 show variables like '%log_bin%'; 2)查看产生的 日志文件. show ...

  8. MySQL最重要的日志-binlog详解

    前言 什么是binlog mysql中有各种类型的日志,记录了mysql包括启动.运行.连接.更改等各种操作,而binlog就是其中最重要的一种日志,它记录了MySQL所有数据的变更,并以二进制的形式 ...

  9. 认真学习MySQL中的二进制日志(binlog)与中继日志(Relay log)

    binlog即binary log,二进制日志文件,也叫作变更日志(update log).它记录了数据库所有执行的DDL和DML等数据库更新事件的语句,但是不包含没有修改任何数据的语句(如数据查询语 ...

  10. mysql正确清理binlog日志的方法

    MySQL中的binlog日志记录了数据库中数据的变动,便于对数据的基于时间点和基于位置的恢复,但是binlog也会日渐增大,占用很大的磁盘空间,因此,要对binlog使用正确安全的方法清理掉一部分没 ...

最新文章

  1. 彻底解决Linux索引节点(inode)占用率高的告警
  2. 李彦宏乌镇谈人工智能:百度会很快和雄安宣布一个大的智能城市计划
  3. 介绍一个好用的工具类库commons-beanutils
  4. 流媒体传输协议---RTP--基础
  5. 图解 Elasticsearch 原理
  6. c++虚继承和虚函数和抽象类、接口类,聚合类
  7. python小案例下载_python 小案例demo06
  8. sklearn自学指南(part49)--字典学习
  9. 函数扩展(函数拦截)
  10. 蔬菜名称大全500种_市场上常见47种室外健身器材型号及名称大全
  11. 【XSY2731】Div 数论 杜教筛 莫比乌斯反演
  12. Win7 旗舰版改为专业版(不用重装)
  13. shell实现简单计算机功能,Shell 实现简单计算器功能(示例代码)
  14. 大数据之Python数据分析 实训 航空公司客户价值分析之二、使用 K-Means 算法进行客户分群
  15. HowTo——cotex-m3处理器HardFault事后分析方法
  16. scrapy 抓取拉钩 ajax
  17. Windows11 输入法图标不见了
  18. Excel中Chart对象成员表
  19. UniAPP HBuilderX 运行到各个小程序开发工具
  20. 专科毕业生该何去何从?

热门文章

  1. 解压zip报错_Get新技能!利用Python自动解压各种压缩文件
  2. Ubuntu dpkg 常用命令教程
  3. 蓝桥杯2019年第十届C/C++省赛C组第一题-求和
  4. Android IPC通信系列篇
  5. 7-36 BCD解密 (10 分)
  6. 十大算法 — 冒泡排序法【C语言代码诠释】
  7. scrapy 在迭代爬取时被拒 offsite 增加dont_filter=True
  8. SharePoint 2013 Deploy Master Page And Page Layout
  9. Tomcat加载类机制 - 我们到底能走多远系列(14)
  10. 使用XML绑定下拉列表