阅读本文大概需要 2.8 分钟。

MySQL 对我说 “Too young, too naive!"

▌大概过程

在测试环境 Docker 容器中,在跨进程调用服务的时候,A 应用通过 Dubbo 调用 B 应用的 RPC 接口,发现 B 应用接口超时错误,接着通过 debug 和日志,发现具体耗时的地方在于一句简单 SQL 执行,但是耗时超过 1000ms。

通过查看数据库的进程列表,发现是有死锁锁表了,很多进程状态 status 处于 'sending data',最后为锁住的表添加索引,并且 kill 掉阻塞的请求,解除死锁,服务速度恢复正常。

下面记录的是大致排查过程:

通过观察业务代码,确认没有内存溢出或者其它事务问题,于是只能考虑 Docker 环境的数据库和 jvm 底层详情了。

▌使用 Druid 监控 SQL 执行状态

通过日志,发现有一句 SQL 严重超时,一句简单 SQL,原本是批量插入多条记录,为了定位问题,测试时 Mybatis 只插入一条记录,但即便如此,还是耗时 10 秒。

于是打算使用阿里巴巴的数据库连接池 Druid 进行监控,监控 SQL 效果如下:

在 SQL 监控 Tab 中,可以看到执行 SQL 的具体情况,包括某条 SQL 语句执行的时间(平均、最慢)、SQL 执行次数、SQL 执行出错的次数等。

上面显示的是正常情况下,时间单位是 ms,正常的 SQL 一般在 10ms 之内,数据量大的控制在 30ms 之内,这样用户的使用体验感才会良好。

所以说之前的 1000ms,是不可接受的结果。

▌通过 JMC 远程监控 Tomcat

 

JMC(java mission control) 是 jdk 自带的一个监控工具,在 jdk 的 bin 目录下(java 大法好,该目录下有很多实用的工具)。

此处加了一个 tomcat 无验证模式:

#在tomcat的conf目录下的catalina.sh增加如下java启动参数:-Dcom.sun.management.jmxremote=true-Dcom.sun.management.jmxremote.port=8888-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=false-XX:+UnlockCommercialFeatures -XX:+FlightRecorder

下面是自己本地调试的截图

然后打开 jmc,创建一个 JMX 连接,输入对应的 ip 和 JMX 端口。接着可以设定一段时间内的飞行监控,监测这一分钟内 jvm 具体参数

当时调试的时候,发现内存使用、CPU 占用率、线程状态也挺正常的,没有发现明显的异常错误,效果如下图:

唯一比较耗时的是在代码 tab 页中,当时发现了大量的 I/O,比上图的比例还高,当时大概占了 80%,查看调用树,很多循环 tcp socket 连接。

考虑到应用中本来就有很多需要 io 以及 netty 也需要 tcp 连接,所以大概排除了 jvm 虚拟机的问题,然后就去排查 MySQL 的问题。

▌排查 MySQL

在了解 MySQL 锁概念的时候,由于现在使用的比较多的是 InnoDB,所以可以着重看看 InnoDB 锁问题。

直接执行 SQL 语句

通过 DEBUG 代码,从 mybatis 中取出映射后的SQL语句,在 MySQL 客户端直接执行 SQL 和 Explain 查看执行计划,速度都很快,排除了 SQL 语句的问题。

查看 MySQL 线程列表

show processlist;

从图中可以看出,有些线程的状态处于 sending data,查阅资料:所谓的“Sending data”并不是单纯的发送数据,而是包括“收集 + 发送 数据”。
然后后面一列 info 显示的是具体信息,是查询用来生成主键 ID 的函数,之前速度都很快,为啥突然就这么慢呢,于是回过头去查看该函数:

select next_value into ret_val from `xxx` where table_name = tableName for update;update `xxx` set current_value=current_value+step,next_value = next_value+step where table_name=tableName;

select for update,给这个表加了排它锁,阻止其它事务取得相同数据集的共享读锁和排他写锁,同时,这个序列表表中,用来检索的字段没有加索引,在 InnoDB 行锁机制中:

由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键(在我们的场景中,就是查询时用到的 table_name),是会出现锁冲突的。

所以了解到其它团队因为查询这个表产生事务问题,造成死锁,这个序列表被锁住了。
由于这个自增序列表每个团队都在使用,所以当时测试环境中,经常有 dao 层超时错误,最终将这些阻塞的线程 kill 掉,为序列表加了索引,解决了问题。

▌小结

下次遇到 MySQL 执行耗时的情况,排除了代码问题之后,要去看数据库是否有死锁的情况存在,观察有没有被阻塞的线程,排查被阻塞的线程具体 info,定位到具体问题。

·END·

程序员的成长之路

路虽远,行则必至

本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。

回复 [ 520 ] 领取程序员最佳学习方式

回复 [ 256 ] 查看 Java 程序员成长规划

一条简单的 SQL 执行超过 1000ms,纳尼?的更多相关文章

  1. 一条简单的 SQL 执行超过1000ms,纳尼?

    作者:VipAugus https://juejin.im/post/5ce906a3e51d455a2f2201dc MySQL对我说"Too young, too naive!" ...

  2. 34条简单的SQL优化准则

    转载地址:http://bbs.csdn.net/topics/260002113 我们要做到不但会写SQL,还要做到写出性能优良的SQL,以下为笔者学习.摘录.并汇总部分资料与大家分享!(1)    ...

  3. 一条简单的 SQL 查询语句到底经历了什么?

    一.MySQL 基础架构   整体来说 MySQL 主要分为两个部分,一个部分是:Server 层,另一部分是:存储引擎层. 其中 Server 层包括有连接器.查询缓存.分析器.优化器.执行器等,存 ...

  4. 转://从一条巨慢SQL看基于Oracle的SQL优化

    http://mp.weixin.qq.com/s/DkIPwbDKIjH2FMN13GkT4w 本次分享的内容是基于Oracle的SQL优化,以一条巨慢的SQL为例,从快速解读SQL执行计划.如何从 ...

  5. 从一条巨慢SQL看基于Oracle的SQL优化(重磅彩蛋+PPT)

    本文根据DBAplus社群第110期线上分享整理而成,文末还有好书送哦~ 讲师介绍 丁俊 新炬网络首席性能优化专家 SQL审核产品经理 DBAplus社群联合发起人.<剑破冰山-Oracle开发 ...

  6. 如何更简单方便地执行SQL操作?

    现在公司使用mybatis作为DAL层的框架. 使用起来比较简单,使用xml进行SQL的书写,java代码使用接口执行. 但在写一些简单SQL的时候会显得非常繁琐: xml和java分离(设计上为了解 ...

  7. 大型面试现场:一条update sql执行都经历什么?

    导读 Hi,大家好!我是白日梦!本文是MySQL专题的第 24 篇. 今天我要跟你分享的MySQL话题是:"从一条update sql执行都经历什么开始,发散开一系列的问题,看看你能抗到第几 ...

  8. 一条sql语句搞定基于mysql的sql执行顺序的基本理解

    对数据库基本操作是每个程序员基本功,如何理解并快速记住sql执行的顺序呢,其实一条复杂的sql就能搞定: SELECT DISTINCT <select_list> FROM <le ...

  9. log4j.xml简单配置实现在控制台打印sql执行语句【加注释】

    转: log4j.xml简单配置实现在控制台打印sql执行语句 2017年09月27日 13:02:34 艾然丶 阅读数 8804   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协 ...

随机推荐

  1. php+js实现极验,拖动滑块验证码验证表单

    现在很多网站,比如淘宝,京东等都改用使用极验拖动验证码实现登录,这种方式比传统的验证码方式有更好的体验,减少用户输入的错误,也同样能起到防盗刷的功能.现在很多极验都是第三方的,也很多都是收费的.今天在 ...

  2. SQL注入流程图

    http://127.0.0.1/sqli-labs-master/Less-2/index.php? id=1 1 输入单引号   ‘            进行检验是否存在输入 http://12 ...

  3. python-Arduino串口传输数据到电脑并保存至excel表格

    起因:学校运河杯报了个项目,制作一个天气预测的装置.我用arduino跑了BME280模块,用蓝牙模块实现两块arduino主从机透传.但是为了分析,还需要提取出数据.因此我用python写了个上位机 ...

  4. JQuery-zTree.js使用范例

    JQuery-zTree.js使用范例 实现Tree树的插件很多,比如常见的UI:Layui.ElementUI.iView ... .这里我们介绍一个小巧的构建Tree树的插件 zTree.js z ...

  5. 实例讲解ip地址、子网掩码、可用地址范围的计算

    关于ip以及相关的掩码.网络号等概念可以查看相关的博客.资料,这些东西很容易找着,一搜一大片.本文主要记录通过实例进行ip相关的计算. 我自己使用的在线网络计算器地址:https://www.sojs ...

  6. The 2019 Asia Yinchuan First Round Online Programming F. Moving On

    t题目链接:https://nanti.jisuanke.com/t/41290 思路:题目意思很容易想到floyd,但是由于危险度的限制,我们该怎么跑floyd呢. 一开始理解错题目了,以为u-&g ...

  7. dfs 正则表达式

    192. 通配符匹配 中文 English 判断两个可能包含通配符“?”和“*”的字符串是否匹配.匹配规则如下: '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). 两个串完 ...

  8. dfs 排列组合——找所有子集(重复元素和不重复元素)

    17. 子集 中文 English 给定一个含不同整数的集合,返回其所有的子集. 样例 样例 1: 输入:[0] 输出: [ [], [0] ] 样例 2: 输入:[1,2,3] 输出: [ [3], ...

  9. 20180520模拟赛T3——chess

    [问题描述] 小美很喜欢下象棋. 而且她特别喜欢象棋中的马. 她觉得马的跳跃方式很独特.(以日字格的方式跳跃) 小芳给了小美一张很大的棋盘,这个棋盘是一个无穷的笛卡尔坐标. 一开始\(time=0\) ...

  10. eclipse 中的注释 快捷键 多行注释快捷键 单行注释快捷键

    Eclipse 中的两种注释方法: (1)多行注释(2)单行注释 一. 多行注释快捷键 1:添加注释Ctrl+Shift+/ :    添加/* */注释 示例:选中代码块后按下快捷键即可 /* fl ...