很多同学吐槽 MySQL 数据同步没有采用物理复制,而是使用逻辑的二进制日志,因此抱怨主从数据同步较慢。

然而,随着基于 WRITE SET 并行复制技术推出,以及 MySQL 8.0 快速加列功能的诞生,只要架构设计得当,MySQL 主从数据延迟的问题几乎已不存在。

相反,姜老师在过去的文章中,一再强调二进制日志是 MySQL 数据库成功的关键。

逻辑日志意味着 MySQL 中的数据不会是一个终点,它可以方便地流向用户想要使用的业务场景。

例如在 MySQL 数据库的数据可以准时时的推送给 ES 做检索,发送给 Spark 做推荐分析,等等。

相比,Oracle、Microsoft SQL Server、PostgreSQL,他们这方面就明显弱很多。

因为,物理日志不好实现异构系统的数据同步。

当然,物理日志 vs 逻辑日志的问题,之前都已分析过。今天讨论的重点是 MySQL 8.0 中关于二进制日志的改进。

通过二进制日志,可以非常容易捕获 MySQL 数据库中的变更,从而推送给其他数据平台。

但是,二进制日志中是否有记录每条记录的元数据信息呢?例如:

  1. 这条记录对应的库名是什么?
  2. 这条记录对应的表名是什么?
  3. 这条记录中每个列的类型是什么?
  4. 这条记录中每个列的名称是什么?
  5. 这条记录中,哪个列是主键?

可以通过命令mysqlbinlog来解析二进制日志,回答上面的问题:

打开网易新闻 查看精彩图片

上面的这张图显示了通过命令 mysqlbinlog 对二进制日志 binlog.000001 的解析结果。

可以看到类型为Table_map的二进制日志event,可以捕获这条记录对应的库名和表名。

类型为Write_rows的二进制日志event,表明这条记录是由INSERT操作记录的二进制日志。

下面的的 @1=3 /* INT meta=0 nullable=0 is_null=0 */ 表示插入记录的列1值为3,类型是INT。

也就是说,对于上面的5个问题,其中3个二进制日志是有保存对应信息的。

然而,二进制日志中并没有记录每个列的名称,以及哪个列是主键的元数据信息。

因此,如果通过二进制日志实现 DTS(Data Transfer Service)服务,需要额外的手段获取这些信息。

业界开源 DTS 做得比较好的是 Maxwell ,简单易用,用 JSON 描述二进制日志中每条记录的信息,并发送到 Kafka :

打开网易新闻 查看精彩图片

通过上面的例子,可以看到 Maxwell 可以捕获每条记录的列名。这里是 id、m、c、comment。

更重要的是, Maxwell 还会记录主键值和主键对应的列

可以发现,上面的例子中,主键是由列 id、c 组成的。

快速扫了下 Maxwell 的源码,发现 Maxwell 实现原理是去查询表 information_schea.COLUMNS ,从而获取这些元数据信息:

打开网易新闻 查看精彩图片

虽然 Maxwell 曲线实现了获取列名和主键的信息,但 MySQL 8.0 版本后,就无需这么复杂的实现了。

因为,上面的元数据信息,将被直接写入到二进制日志。

MySQL 8.0 版本允许将每条记录的列名和主键信息记录到二进制日志的 Table_map event中。

这个新特性默认关闭,需要通过将参数 binlog_row_metadata 设置为 full 才能打开此特性:

mysql > SET GLOBAL binlog_row_metadata = full;

之后,再通过命令 mysqlbinlog ,再加入新参数 --print-table-metadata 就能打印出每条记录的列名和主键信息了:

打开网易新闻 查看精彩图片

显然,这个特性会增大二进制日志的容量,但如果计算下 Table_map event的增长,其实会发现只从47字节增长为了65字节,开销并不是特别大。

当然,如果你表字段非常多,那么增长的幅度就会相对比较大了。

不过,当二进制日志包含了每条记录的值和元数据信息, DTS 就变得非常 easy 了。

更重要的是,每次表结构发生 DDL 变更时,也不用进行额外的处理。

今天的文章介绍了 MySQL 8.0 对于二进制日志的一个改进。

通过设置参数 binlog_row_metadata 为 FULL ,可以在二进制日志中包含每条记录的所有元数据信息。

虽然对于二进制日志存储来说,会增加一定的存储开销。

但对于异构系统之间的数据同步来说,这个特性会非常有用。

最后,姜老师想说的是,都2021年了,你还不升级到 MySQL 8.0 这个伟大的版本么?

伟大航路,即将启航~~~