当前位置:首页 >> 主机教程

常见SEO阿里云服务器域名映射记一次MySQLCPU被打满的SQL优化案例分析

发布时间:2025-12-20 16:49:33 作者:熊猫主机教程网
简介 日本云服务器歌舞团脱 背景介绍 系统中有个公告模块,当用户登录后,根据用户所属机构查询公告列表,同时公告列表中需要展示出该用户对公告的阅读状态及阅读时间。公告(bulletin)、公告接收者(bulletin_receiver)、公告阅读者(bulletin_reader)定义及关联关系如下: 实体及实体关系

日本云服务器歌舞团脱

背景介绍

系统中有个公告模块,当用户登录后,根据用户所属机构查询公告列表,同时公告列表中需要展示出该用户对公告的阅读状态及阅读时间。公告(bulletin)、公告接收者(bulletin_receiver)、公告阅读者(bulletin_reader)定义及关联关系如下:

实体及实体关系

应用使用的数据库连接池是druid,数据库是阿里云RDS MySQL 5.6(16c64g)

问题梳理

经过梳理,事件时间线大概是这样的:

事件时间线

14:45 GetConnectionTimeoutException

GetConnectionTimeoutException

CPU & Memory

14:47 钉钉报警

报警信息

14:59 CommunicationsException

CommunicationsException

问题分析

应用分析

GetConnectionTimeoutException

连接超时异常处理逻辑

arthas vmtool

我们分析问题,通常会碰到日志记录不够排查问题的情况,此时可以通过arthas相关命令进行分析。比如我们想看一下druid连接池统计信息。

统计信息概览

SQL统计信息

CommunicationsException

阿里云服务器按量计费

出现该异常几个典型场景是:

数据库连接空闲时间超过了MySQL服务器配置的wait_timeoutMySQL server versions like 5.6.25 and earlier or 5.7.5 and earlier,客户端连接属性useSSL默认是false;MySQL server versions like 5.6.25+ or 5.7.5+,客户端连接属性useSSL默认是true。默认useSSL=true的MySQL server版本,客户端连接属性还需要配置其他额外的连接属性,如果没有配置会抛出_CommunicationsException异常。_客户端发送请求后,服务端比较忙,一直没有回复客户端的请求导致超时。

从上面时间线看,当出现该异常的时候,MySQL CPU已经被打满,无法及时处理客户端请求,导致客户端请求超时。

超时场景

系统负载

系统负载

业务指标

业务入口请求量比较平缓,没有波动系统GC情况正常… …

数据库分析

数据库侧没有打开performance_schema,主要排查操作:

九三云服务器

show processlist:查看数据库会话信息select * from information_schema.innodb_trx查询慢SQL:没有慢SQL

可疑SQL:

SELECTA.IDASID, A.BULLETIN_TYPEASBULLETIN_TYPE, A.BULLETIN_CONTENTASBULLETIN_CONTENT, A.STATUS_CODEASREMARKS, B.READ_STATUSASSTATUS_CODE, B.READ_TIMEASGMT_MODIFIEDFROM(SELECTC.*FROMBULLETIN CWHEREC.IDIN(SELECTD.BULLETIN_IDFROMBULLETIN_RECEIVERASDWHERED.RECV_CODEIN(45346600,45302600)GROUPBYD.BULLETIN_ID)ANDC.STATUS_CODE=RELEASEANDC.BULLETIN_TYPE=2ANDC.VALID_DATE_END>2022-11-16 00:00:00ANDC.VALID_DATE_BEGIN<=2022-11-17 00:00:00)ASALEFTJOINBULLETIN_READERASBONA.ID= B.BULLETIN_IDANDB.READER_ID=1990234WHEREB.IS_DELETEDISNULLORB.IS_DELETED=0LIMIT0,10

explain 执行计划:

执行计划

似乎没有啥问题,而且SQL执行的还可以。一时没有好的办法快速解决,扩容了两台从库用来分担读的流量,从库上线后一切还算正常,于是恢复了部分数据,哪知过了两天CPU再次被打满… …问题分析到这里,似乎已经不是资源的问题了… …

解决办法

SQL优化

话说SQL里尽量不要使用IN,可以使用EXISTS或JOIN替代,于是我们改了下SQL。

EXISTS

SELECTA.IDASID, A.BULLETIN_TYPEASBULLETIN_TYPE, A.BULLETIN_CONTENTASBULLETIN_CONTENT, A.STATUS_CODEASREMARKS, B.READ_STATUSASSTATUS_CODE, B.READ_TIMEASGMT_MODIFIEDFROM(SELECTC.*FROMBULLETIN CWHEREEXISTS(SELECT1FROMBULLETIN_RECEIVERASDWHERED.BULLETIN_ID=C.IDANDD.RECV_CODEIN(45346600,45302600) )ANDC.STATUS_CODE=RELEASEANDC.BULLETIN_TYPE=2ANDC.VALID_DATE_END>2022-11-16 00:00:00ANDC.VALID_DATE_BEGIN<=2022-11-17 00:00:00)ASALEFTJOINBULLETIN_READERASBONA.ID= B.BULLETIN_IDANDB.READER_ID=1990234WHEREB.IS_DELETEDISNULLORB.IS_DELETED=0LIMIT0,10

执行计划

JOIN

除了将IN改为JOIN,同时将select中的公告内容字段去掉,因为多数场景下公告列表不需要内容字段。

SELECTA.IDASID, A.BULLETIN_TYPEASBULLETIN_TYPE, A.STATUS_CODEASREMARKS, B.READ_STATUSASSTATUS_CODE, B.READ_TIMEASGMT_MODIFIEDFROM(SELECTC.IDASID,C.BULLETIN_TYPEASBULLETIN_TYPE,C.STATUS_CODEASSTATUS_CODEFROMBULLETIN CJOIN(SELECTD.BULLETIN_IDASIDFROMPOR_BULLETIN_RECEIVERASDWHERED.RECV_CODEIN(45346600,45302600)GROUPBYD.BULLETIN_ID )ASEONC.ID=E.IDANDC.STATUS_CODE=RELEASEANDC.BULLETIN_TYPE=2ANDC.VALID_DATE_END>2022-11-16 00:00:00ANDC.VALID_DATE_BEGIN<=2022-11-17 00:00:00)ASALEFTJOINBULLETIN_READERASBONA.ID= B.BULLETIN_IDANDB.READER_ID=1990234WHEREB.IS_DELETEDISNULLORB.IS_DELETED=0LIMIT0,10

执行计划

验证

无论执行计划怎么样,还是实际验证下比较放心。

验证逻辑

结论

IN、EXISTS性能几乎无差别,每次请求平均耗时56ms,JOIN每次请求平均耗时1ms。

服务拆分

公告模块目前与核心模块耦合有点紧,当公告模块出现问题的时候会直接影响到核心模块,需要将公告模块进行拆分。

公告内容字段存储优化

方案一

将公告内容字段独立到一个表中

方案二

目前公告字段是存储在MySQL中,大小从60B 到 25KB不等,从上面分析看这个字段对系统的伤害非常大,可以考虑将该字段放到OSS存储,数据库中保存OSS路径的方式。

存储优化简介

完善监控

当发现我们掌握的信息不足以分析问题的时候,说明需要完善现有的监控指标

数据清理

根据数据保存规定,将过期数据及时清理出去。

服务器公有云