MySQL Binlog用于记录用户对数据库操作的结构化查询语言(Structured Query Language,SQL)语句信息。是MySQL数据库的二进制日志,可以使用mysqlbin命令查看二进制日志的内容。爱奇艺在会员订单系统使用到了 MySQL Binlog,用来实现订单事件驱动。在使用Binlog 后在简化系统设计的同时帮助系统提升了可用性和数据一致性。
背 景 Binlog 是 MySQL 中一个很重要的日志,主要用于 MySQL 主从间的数据同步复制。正是因为 Binlog 的这项功用,它也被用于 MySQL 向其它类型数据库同步数据,以及业务流程的事件驱动设计。通过研究分析,我们发现使用 MySQL Binlog 实现事件驱动设计并没有想象中那么简单,所以接下来带大家了解 MySQL 的 Binlog、Redo Log、数据更新内部流程,并通过对这些技术原理的介绍,来分析对业务流程可能造成的问题,以及如何避免这些问题。希望通过本文的解析,能够帮助大家了解到 MySQL 的一些原理,从而帮助大家能够更顺利地使用 MySQL 这个流行的数据库技术。
图中描述了 update 语句执行过程中 MySQL 执行器、InnoDB,以及 Binlog、Redo Log 交互过程(图中深绿底色的是 MySQL 执行器负责的阶段,浅绿底色是 InnoDB 负责的阶段)
问题解析 从上面对 MySQL 原理的介绍我们得知,写 Binlog 发生在事务提交阶段,但是 MySQL 因为在 Server 层和存储引擎层都引入了不同的日志结构,从而引入了两阶段提交。Binlog 的写入发生在存储引擎真正提交事务之前,这导致理论上通过 Binlog 同步数据的系统(MySQL 从库、其它数据库或业务系统)有可能早于 MySQL 主库使最新提交的数据生效。
所以上面提到的订单履约服务在收到基于 Binlog 的订单支付事件后却查到相应订单是未支付的,原因很可能是订单履约服务在查询数据时,订单支付数据更新操作在 MySQL 内部尚未彻底完成事务的提交。
我们通过开发验证程序重现了这一现象。验证程序接收到事务提交完成后的完整 Binlog 时会再次在 MySQL 主库上查询对应的记录,结果会有一定概览获得事务提交前的数据。