RDS/MSSQL CPU持续飙高问题分析

一:背景介绍
公司数据库使用的是阿里云RDS服务,有SQL Server和MySQL两种数据库;本次事故是其中一个核心也业务产品线使用的SQL Server数据库。
相关参数如下(逼格不算低贵司不差钱RDS/MSSQL CPU持续飙高问题分析):
  • 规格代码: rds.mssql.c2.xlp2
  • 数据库版本:SQL Server 2008 R2
  • 数据库架构:Mirror
  • 配置:16 核 /96GB/连接数:24000 IOPS:16000 
  • 数据量:120GB
二:问题描述
2016/6 /18日周六早上相关部门反映前端做单缓慢,查看数据库监控发现数据库CPU持续飙高,从监控中看到其实从从6/17日晚17点开始CPU飙高到60%持 续到做单结束23点,因为不是订单高峰期,所以没有被发现;6/18日早上09:50继续飙高到60%-80%直到晚上20:30。
认真分析这两天的监控数据发现, 其他指标如全表扫描数,数据库连接数,网络流量流入流出,每秒登录次数和平均每秒SQL语句执行次数都没有大的波动,都很正常;但平均每秒事务数相当异常, 最高达到了近40000次/秒(平时1000左右,近40倍) 。
后来时不时,但不是很频繁(每两三个礼拜)都会发生类似的事情,导致大家都很紧张,幸运的是导致业务做单慢,但没有卡死(寻求小小的自我安慰RDS/MSSQL CPU持续飙高问题分析)。
相关监控截图(10月份的):
CPU
RDS/MSSQL CPU持续飙高问题分析
平均每秒事务数:
RDS/MSSQL CPU持续飙高问题分析
10/17日两个小时内IOPS监控,很有规律,2-3分钟会有峰值
RDS/MSSQL CPU持续飙高问题分析
三:处理过程
通 过脚本和阿里DMS控制台并没有发现有任何阻塞,SQL处理速度正常(手动刷的RDS/MSSQL CPU持续飙高问题分析其实这是一种幻觉,问题就埋在此处)。发现有一个IX锁,是技术支持客户端登录 产生的,但他是只读权限,在线下模拟只读权限下IX锁并不会影响事务操作,不会锁表;后来有联系该技术支持把电脑关闭,IX锁在20:30左右消失,但这个点TPS也恢复了正常(牛头对上了马嘴后来才知是干扰线索)。
初步怀疑是因为这个 IX锁影响到RDS后端,导致执行一些事务(于是想这个锅要阿里来背了RDS/MSSQL CPU持续飙高问题分析)。找不到原因,业务单量没有变化,为什么每秒事务数会莫名的高出30-40倍呢?只能怀疑一切怀疑阿里了,但跟阿里工单和电话沟通确认后,他们否认是这个原因;因线上没有开启profile审计(RDS是不开放此权限的),所以他们也无法判断是什么引起。后来有请阿里临时开通账号的profile权限,下次问题重现时可以通过profile定位具体的事务。问题没有根治,但第二天又诡异的恢复正常了;于是就更加云里雾里,当时总结如下:
  1. 把技术支持跳板机空闲时间设定15分钟不活动即log off,强行个人用户超过空闲时间就断开数据库连接。
  2. 有确认业务慢对应到的物理表,一个2000W+,一个近1000W,找到研发负责人进行优化。
  3. 优化慢查询,对超多100ms以上的慢SQL格杀勿论,跟研发的同学配合优化
  4. 线上出现问题后可以通过阿里后台提升权限来排查问题

但后面时不时的又来了,持续一两天又消失的无影无踪(真是来无影去无踪),搞得大家鸡犬不宁的;后来出问题时有请阿里开启profile也没有定位到具体原因;就 这样持续了三四个月;在四个月后的10/19日下午中午找到了元凶,在分析做单业务时有找到一个物理表,数量很小(个位数)用于存放客服人员提交的Job 请求,该请求数据被查询后会随即删除,所以高峰期也不会超过100的量,所以之前维护索引时根本没有在意,想着根本不会有性能问题,建索引意义也不大;把 查询这张表的SQL取出来到离线环境(T+1)测试,竟然需要消耗在80~90ms(没有在我们定义的慢查询范围内,前面提到的手动刷或执行命令根本抓不到),奇怪的是为什么几行的数据要花费这么久,于是SET STATISTICS IO/TIME ON,并打开实际执行计划,执行后一下惊呆了,逻辑读竟然达到了近10000页,10000*8kb=80MB的数据;跟研发确认得知这个表的写/读/删的频率很高,有200+个客服人员同时操作,所以每秒的并发就可想而知了。因为这个表吞吐量产生瓶颈,所以做Job的事务被拖长了,事务数也持续增高, 这样就可以解释通了。
至于MSSQL表很小但查询为什么会有那么大的逻辑读请参照以下解释:
1、删除表数据实际上不是物理删除,记标志位,记录数据是否使用(删除后数据文件并不会变小);
2、新的数据进来后会复用被标记删除的页空间;
3、表的空间没有被回收执行SQL时仍需要遍历所有页面,导致实际的逻辑读要比理论上大的多,并发上来后响应就慢下来了;
道原因处理起来就很简单了,最快的办法是把表rebuild下,再执行查询就是0-1ms了;再观察数据库CPU是嗖嗖嗖的降下来了,对症下药终于解决 可以安心的睡觉了。然后排个任务半个小时执行下,长远来看的话要求研发添加缓存(典型的缓存场景,技术债啊),数据存取到redis不需要存储在持久层。
四:事后总结
历时3~4个月问题总算得以解决,也对生产做单产生了一定影响,最大的感触是DBA了解业务是多么的重要;但还有一些疑惑点,为什么CPU不是一直飙高,而是偶尔出现一两天然后消失?因为有设置SQL Server维护计划每天凌晨执行,更新统计信息、rebuild或reorgnize索引碎片率高的索引,估计就是这个Job回收了表空间后恢复正常了,累积一段时间后又爆发了。

上一篇:tomcat通过socket连接MySQL,不再占用服务端口【linux】


下一篇:sql bypass waf fuzz python