往期分享
RDS MySQL
RDS PostgreSQL
RDS SQL Server
Redis
MongoDB
概述
CPU做为数据库资源最核心的资源,是日常最重点需要关注的指标,CPU用满,会导致应用RT增高、业务卡顿,更严重会导致数据库实例hang死发生ha等问题,严重影响日常生产业务。
一般对于CPU的监控需要设定安全水位,超出安全水位要及时处理,否则会引发不可预期的严重后果。
真实业务CPU使用
随着业务增长,在数据库上线之初采购的数据库实例规格可能已经跟不上业务流量的上涨,此时由于流量增长,数据库的使用逐渐在加重,此类的CPU上涨是随着业务逐渐升高的,如果从性能曲线观察,必有某一指标是上涨趋势,和CPU曲线上涨曲线拟合,如qps/iops等等,图例(图中cpu使用率不高,只做为趋势表示,可以看到qps和cpu曲线表现基本一致):
此时,如果CPU出现瓶颈,基本可以认为是实例资源上限已不足以支持业务流量,此时最好对实例进行节点或者规格扩容。
1.大量业务都是读请求,可以通过增加只读节点,进行集群横向扩容,以分流读流量
2.大量业务都是写请求,此时对ro节点进行扩容不会对性能起到提升作用,需要对规格进行扩容变更,如:由4C规格变更为8C规格:
非预期内CPU增长
导致CPU非预期增长的情况比较复杂,此文暂列几种常见的问题,随着生产环境中不断发现会对本文进行补充。
慢查询导致
一般来说,CPU增长,有很大部分原因是由于SQL语句不合理,产生慢查询,同时产生活跃线程堆积导致CPU打高,但是一定要区分真实慢查询和其他原因导致的慢查询,换句话说:是因为慢查询导致CPU高或者是由于其他资源打满导致查询变慢。
在控制台的慢查询分析中可以看到慢查询情况
如果慢查询中有内容,就需要对慢查询进行分析,如果是慢查询导致CPU资源用尽,有一个比较明显的特性就是读取返回比非常高:
简单理解就是扫描行远远大于返回行数,注意此处要排除掉count类查询,有可能一些AP类查询的确扫描行数很大,此处先针对TP类查询进行分析。
TP类业务基本都是读写非常小量的数据量,如果此类查询的扫描数据量非常大,那么大概率原因是由于索引缺失导致,例如
select*from tb1 where name='testname';
例如此查询在慢查询列表中显示扫描数据量1万+,返回数据一条,那么很明显在name列上有索引缺失的情况,可以通过
show index from tb1;
确认在name列上有索引,如果没有,可以添加索引列
altertable tb1 add key ix_name (name);
消除此类大数据量扫描导致的慢查询。
如果发现name列上有索引,此时可以通过
explain select*from tb1 where name='testname';
查看语句的执行计划,确认是否使用的正确的索引,假如发现name列存在索引,但是并没有使用,有可能出现了统计信息不准确导致生成了错误的执行计划,可以通过
analyze table tb1;
重新生成表上的统计信息用以纠正错误计划,执行完成后,再进行explain确认是否使用的正确的索引。
索引相关知识比较复杂,请自行搜索相关资料进行学习。
活跃进程高
活跃进程高一定会带来CPU使用的增长,抽象的说,MySQL实现中,每一个CPU只能在同一时间处理一个请求,也就是说,假设是16C规格的实例,最多只能同时处理16个请求,但是一定要注意,这个请求是指的内核层面,而非应用的并发层面。
如果排除掉慢查询导致的请求无法正常消化,活跃进程堆积一般都是由于真实业务流量增长带来的,如果查看曲线,整体流量以及请求趋势都是和活跃进程的堆积趋势一致,那代表实例规格已经到达峰值,此时一般都要通过实例扩容解决,请参考[真实业务CPU使用] 部分进行节点或者规格扩容。
但要注意,在活跃进程达到临界点时,可能在CPU层面开始产生争抢,内核中产生大量的mutex 排他锁,此时曲线一般表现特征为: 高CPU,高活跃进程,低IO或低qps。
还有一种情况是突然的业务洪峰,建立连接速度非常快,也可能导致大量争抢导致请求堆积。
此类问题一般可以通过开启实例thread_pool特性进行流控缓解,需要在实例的参数设置中,打开 thread_pool_enabled选项,基本可以对此类问题有所缓解。
但是要注意,如果活跃进程有所缓解,同时还要注意应用侧是否已经产生了业务堆积,如果CPU负载较高同时活跃进程依然高居不下,此时则同样要考虑是不是对实例进行扩容操作。
另有一种情况是前端连接风暴导致实例流量瞬间堆积,此时流量属于异常流量,一般可能出现数据被爬虫拉取数据的场景下,此时可以通过sql限流的方式进行请求拒绝,通过一键诊断->会话管理 入口进行自助sql限流操作:
内核配置不合理
云上RDS参数是通用场景下的标准配置,对于各别业务可能不太适用,需要进行详细微调,有些问题在上线初期数据量少的情况下不会触发,但是随着时间推移,数据量增大,会在特定条件下触发。
比较常见的问题会出现在内存使用争抢,在MySQL体系中,内存很大部分是做为数据缓存,也就意味着数据需要不断的迭代,最常用的两块内存是Buffer Pool和innodb_adaptive_hash_index 两块内存区域。整个数据库系统的缓存区域,是数据交换最为频繁的位置,如果内存不足和内存页争抢,则会出现各种异常的堆积和慢查询,最典型的表现是数据库突然CPU上涨打满,并且出现慢查询,排查后可以确认并非索引缺失,这种情况下就有可能是内存系统发生了问题。
例如在进行truncate table操作时,MySQL要遍历Buffer pool将truncate 表的数据页全部驱逐,此时如果大规格的实例,innodb_buffer_pool_instances配置为1并且并发相对较高的情况下,就有可能出现争抢问题。
这个问题在业务上线初期就可以发现,一般来说可以将innodb_buffer_pool_instances的值配置与CPU core数量对齐,将Buffer Pool进行分桶,就可以规避此类问题。
另外还有一种情况是innodb_adaptive_hash_index出现争抢,比较明显的表现是执行
show engine innodb status;
时会出现大量的 hash0hash.cc 等待,在 AHI显示段中,会出现明显的数据倾斜,如图:
此类问题可以将innodb_adaptive_hash_index参数关闭,也就是直接弃用AHI特性,已有数据表明在混合读写的场景下AHI也有可能带来负面的性能影响,关闭后对整体业务的影响不是很大。
BUG
BUG是相对少见的问题,例如比较早的进程死锁、表上统计信息置0导致全表扫描等等,但是随着产品的快速迭代,BUG导致的CPU问题相对不多,但是由于排查涉及更多内核层面信息,客户自助处理可能有一定难度,在以上手段调整后还是出现CPU问题,请工单与阿里云进行联系进行排查。