踩坑MySQL主从延迟背景下,流程业务卡住无法流转,问题得以暴露。

背景

今天这个问题我们的监控没有提前观测到,属于业务处理时未考虑到主从同步,用户反馈过来时,距离问题发生其实已经过去了几天。

我们有个业务流程表:t_apply,基本流程:

  1. 我们的服务端应用biz-server接收到用户提交的数据,创建一条申请单数据。
  2. 触发外部依赖的一个校验服务validation-server,这个校验动作一般耗时:10ms-10s。
  3. 校验服务处理完成后回调biz-server接口,更新我们的申请单状态。

很清晰、简单的一个流程。

其中1-2隐含了MySQL主从复制的过程。

而今天爆出的业务问题时:数据提交了,申请单状态却卡在了INIT状态,也就是校验状态未成功回写。

正常的状态变化:INIT->NODE1。同时,我们的业务MySQL一个实例被多个业务方共享。

问题排查

查日志

出现问题先查日志: 发现回调是有触发的,而回调内的更新状态的sql却没有执行(对应日志没打出来)。

疑问

什么情况会导致select出的数据是空的呢?正好我们前两天刚好解决过一个主从同步延迟导致的问题,所以经验告诉我:发生了主从同步延迟。

验证

查问题还是应该有依据才能得出可靠的结论。对照了两个时间点:

  • 数据创建的时间点:Thu Dec 16 2021 18:47:25 GMT+0800 (China Standard Time)
  • 校验服务回调的时间点:Dec 16, 2021 @ 18:47:33.387

耗时秒级别,属于前期接入此校验服务时正常预期范围。

观察数据库监控大盘: 12.19这种无类似问题时候的数据库整体状态

12.20过去一周的数据库整体状态 对比16号的TPS与最近一周的TPS数据,发现平时TPS大约为500,而16号达到了差不多7k的量。到这里已经可以看到12.16下午六点多开始出现数据库流量尖刺。

12.16当天下午dml尖刺 如上通过数据库的监控大盘,我们找到了问题(主从复制延迟)以及问题原因(DML尖刺带来TPS激增)。

综上,我们画出问题对应时序图: 当前问题发生的过程时序图 时序图帮助我们更形象地表达问题过程。

问题解决

到此我们定位到了问题:主从复制延迟。 以及分析出了问题原因:DML尖刺带来TPS激增。

同时为了更好地解决问题,我拜托了DBA大佬帮忙导出了16号18点到19点的DML语句(解析binlog行),这一步可以帮助我们分析是否为其他公用MySQL资源的业务方带来的DML流量尖刺。

资源充足

经分析对应时段DML语句,我们发现有很多数据写入是其他业务带来的,如果资源充足,我们可以隔离多个业务间的DB资源。

资源不太充足 | 业务要求不高

DB资源没那么充足或者业务要求并没那么高(这里主要指MySQL主从复制的延迟容忍度)的情况下,比如今天排查的这个应用属于集团toB业务,资源要求不高,那么我们不单独申请DB资源。

在这个框架内,我们依然可以改善、解决问题:

  • callback业务方法或者对应select语句处,强制指定主节点数据源:@DS("master")
  • callback业务方法处:指定事务:@Transactional(rollbackFor = Throwable.class),使用的mybatis-plus主从切换如果在事务内默认读主节点数据

同时排除带来DML尖刺的业务操作(超出了当前数据库处理的能力)。

数据库优化

主库的TPS并发越高,产生的DML数量就越超过slave单线程的处理能力,延迟也就越大。新版本MySQL主从复制已支持多线程,因此升级MySQL是一个优化点。如果此时slave查询锁等待过多,也会影响复制进度。

反思

纵观整个过程,你会发现,这又是一例因为错误实现导致的问题。所以:

  • 提高团队的战斗力志在必行。
  • 问题解决后带来的是宝贵的经验,珍惜问题,把每个问题解决好。
  • 实现一个方法的时候,最好同时能有整体架构的高度思考。

Ref