从“订单不存在”异常出发,窥探mysql数据库redo日志和binlog的一致性问题
问题缘起
公司的公共订单服务线上有一个场景:上游业务系统监听订单库binlog,如果有新订单产生,那么根据binlog中的订单id字段,来反查订单服务的查询接口,获取该订单的详细信息;
但在该服务上线后,订单服务的报警群里经常能发现一类由于该查询引发的订单不存在异常,然后立刻通过一次重试,又能查到该订单了,最开始的想法是这些查询一定是走到了从库,是由于数据库主从同步延迟的原因,没有查到该订单信息;
失败的修复
基于这个假设,订单服务开放了一个查询主库的接口,在该接口的sql语句里加入强制查询主库的前缀(能通过公司的dbproxy路由到主库),并让该上游业务系统走该接口;但是该流程上线后,并没有发现该类错误有减少;
这就有点出乎意料了:上游系统收到mysql的binlog消息后再去反查主库,此时该条binlog的对应数据,可能会在数据库中还没落盘吗?
数据库内部的两阶段提交
要解答该问题,需要了解mysql的redo日志刷盘以及binlog的产生顺序。首先先简单介绍一下redo日志和binlog日志;
我们知道mysql innodb引擎为了保证事务的持久性,用redo日志做宕机后的数据恢复;而mysql的binlog日志用于数据库的主从数据同步。为了保证