一次Mysql update sql不当引起的生产故障记录


Posted in MySQL onApril 01, 2022

故障表现

  • 一方面 :在阿里云控制台云数据库PolarDB对应的集群管理页面上,在诊断与优化模块里面的一键诊断会话管理中,发现某条update sql 执行时间非常久且非常频繁;

  • 另一方面:业务监控系统中开始不断有业务执行时间发出告警信息提示,且告警的业务数据不断上升,部分操作影响客户使用。

业务背景

由于业务操作涉及到的业务流比较复杂,对纯技术的分享来看,不是重点讨论的话,为了更有利于理解问题发生的原因,使用类比的方式,把复杂的业务类比成如下描述: 有数据库3张表,第一张表t_grandfather (爷表),第二张表为t_father(父表),第三张表t_grandson(子孙表),DDL如下:

CREATE TABLE `t_grandfather ` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `count` int(11) NOT NULL DEFAULT 0 COMMENT '子孙后代数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='老爷表';

CREATE TABLE `t_father ` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `grandfather_id` int(11) NOT NULL COMMENT '老爷表id',
  PRIMARY KEY (`id`),
  KEY `idx_grandfather_id` (`grandfather_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='老爸表';

CREATE TABLE `t_grandson` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `grandfather_id` int(11) NOT NULL COMMENT '老爷表id',
  PRIMARY KEY (`id`),
  KEY `idx_grandfather_id` (`grandfather_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='孙子表';

三张表之间的业务逻辑关系为,先生成老爷表,然后这个老爷取很多老婆(业务),会不断的生娃,生一个娃就会生成一张老爸表,同时会更新老爷表的count=count+1,表示新增一个后代了,老爷的老婆(业务)在不断的生娃的时候,之前的生的娃也会有老婆,他们的老婆也会生娃,对老爷来说,就是它有了孙子(产生新的业务数据),那有了孙子之后也需要更新老爷表的count=count+1,表示新增一个后代了,以此类推,子子孙孙无穷尽也(业务数据不断生成) 如下图所示:

一次Mysql update sql不当引起的生产故障记录

祖传代码的逻辑为,只要是t_father表和t_grandson有新增,就去更新t_grandfather。这个逻辑设计上问题不大,不过考虑到孙子表数据量很猛的时候,这里就会出现一个非常严重的性能问题。以下是业务摘取的一部分伪代码

/**
 * 处理 father 的业务
 */
 public void doFatherBusiness  (){
     //do fatherBusiness baba .... 此处省
     // 插入 t_father 表
    if (fatherMapper.inster(father)){
         //update t_grandfather set count=count+1 where id= #{grandfatherId}
         grandfatherMapper.updateCount(father.getGrandfatherId  ())  ;
     }
}


 /**
 * 处理 grandson 的业务
 */
 public void doGrandsonBusiness  (){
     //do grandson baba .... 此处省略
     // 插入 t_grandson 表
     if(grandsonMapper.inster(grandson)){
          //update t_grandfather set count=count+1 where id= #{grandfatherId}
          grandfatherMapper.updateCount(grandson.getGrandfatherId());
     }
}

当多个业务(线程)分别调用上面的方法时,都会对t_grandfather表的更新操作造成巨大的压力,特别是更新同一个id的情况下,mysql server内部对锁的竞争非常激烈。最后表现出来就如前文背景描述的一致。

解决方案

1. 临时处理方案:

一方面,在阿里云控制台,对sql进行限流,在正常阻塞的会话,强制kill掉,让数据的线程不阻塞着,释放资源,另外一方面,在把接收请求的服务减少节点数,目的是减少业务数据量进入;

2. 长久方案

一方面更改掉上面的业务逻辑,插入t_grandson表和t_father表时,不在去更新t_grandfather表的count字段;另一方面,需要用到count统计需求时,全部切换成别的方式;

总结

到此这篇关于一次Mysql update sql不当引起的生产故障的文章就介绍到这了,更多相关Mysql update sql生产故障内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
left join、inner join、right join的区别
Apr 05 MySQL
MySQL慢查询的坑
Apr 28 MySQL
MySQL 8.0 Online DDL快速加列的相关总结
Jun 02 MySQL
MySQL如何解决幻读问题
Aug 07 MySQL
MySQL分区表实现按月份归类
Nov 01 MySQL
关于mysql中时间日期类型和字符串类型的选择
Nov 27 MySQL
MySQL的InnoDB存储引擎的数据页结构详解
Mar 03 MySQL
浅谈如何保证Mysql主从一致
Mar 13 MySQL
排查并解决MySQL生产库内存使用率高的报警
Apr 11 MySQL
MySQL视图概念以及相关应用
Apr 19 MySQL
mysql中关键词exists的用法实例详解
Jun 10 MySQL
MySQL的意向共享锁、意向排它锁和死锁
Jul 15 MySQL
Mysql超详细讲解死锁问题的理解
Nebula Graph解决风控业务实践
MySQL实现配置主从复制项目实践
Mysql多层子查询示例代码(收藏夹案例)
Mar 31 #MySQL
MySQL Server层四个日志的实现
分享几个简单MySQL优化小妙招
MySQL Server 层四个日志
You might like
PHP 文件类型判断代码
2009/03/13 PHP
discuz7 phpMysql操作类
2009/06/21 PHP
php simplexmlElement操作xml的命名空间实现代码
2011/01/04 PHP
php利用ffmpeg提取视频中音频与视频画面的方法详解
2017/06/07 PHP
php+Ajax处理xml与json格式数据的方法示例
2019/03/04 PHP
对象的类型:本地对象(1)
2006/12/29 Javascript
jQuery 使用手册(七)
2009/09/23 Javascript
javascript 主动派发事件总结
2011/08/09 Javascript
jQuery提交表单ajax查询实例代码
2012/10/07 Javascript
javascript 构造函数强制调用经验总结
2012/12/02 Javascript
用jQuery实现一些导航条切换,显示隐藏的实例代码
2013/06/08 Javascript
js获取页面及个元素高度、宽度的代码
2016/04/26 Javascript
浅谈json取值(对象和数组)
2016/06/24 Javascript
jquery实现界面无刷新加载登陆注册
2016/07/30 Javascript
Highcharts学习之坐标轴
2016/08/02 Javascript
ReactJs快速入门教程(精华版)
2016/11/28 Javascript
Javascript 两种刷新方法以及区别和适用范围
2017/01/17 Javascript
深入理解javascript的getTime()方法
2017/02/16 Javascript
vue-cli+webpack记事本项目创建
2017/04/01 Javascript
简单实现jquery隔行变色
2017/11/09 jQuery
手写简单的jQuery雪花飘落效果实例
2018/04/22 jQuery
浅谈react-router@4.0 使用方法和源码分析
2019/06/04 Javascript
layui实现下拉复选功能的例子(包括数据的回显与上传)
2019/09/24 Javascript
javaScript 实现重复输出给定的字符串的常用方法小结
2020/02/20 Javascript
python Django模板的使用方法(图文)
2013/11/04 Python
通过python连接Linux命令行代码实例
2020/02/18 Python
Django 用户登陆访问限制实例 @login_required
2020/05/13 Python
详解python logging日志传输
2020/07/01 Python
银行类自荐信
2014/02/04 职场文书
《金钱的魔力》教学反思
2014/02/24 职场文书
2014年教研组工作总结
2014/11/26 职场文书
用php如何解决大文件分片上传问题
2021/07/07 PHP
CKAD认证中部署k8s并配置Calico插件
2022/03/31 Servers
SpringBoot 集成短信和邮件 以阿里云短信服务为例
2022/04/22 Java/Android
使用CSS自定义属性实现骨架屏效果
2022/06/21 HTML / CSS
python运行脚本文件的三种方法实例
2022/06/25 Python