在日常工作中,当你发现MySQL的状态不对时,通常会查看监控指标,经常会看到一个熟悉的场景:CPU占用率再次爆发。本文将为您介绍MySQL与CPU的关系。对此有了一定的了解之后,就可以更加准确的判断问题的原因,也可以提前发现一些导致CPU出现问题的隐患。如何理解CPU使用率以Linuxtop命令为例,效果如下:Top命令在%CPU列显示CPU使用率,百分比是指整体时间百分比:%us:表示用户进程CPU使用时间(不是nice调度的)%sy:表示系统进程的CPU使用时间,主要是内核使用。%ni:表示用户进程通过CPU调度(nice)的使用时间。%id:空闲CPU时间%wa:运行时等待IO的CPU时间%hi:处理硬中断花费的CPU时间%si:处理软中断花费的CPU时间%st:CPU时间通常被虚拟机窃取在某些情况下,CPU我们讨论的usageistoohigh,指的是%us这个指标,monitor中的CPUusage一般就是这个值(也可以通过其他方法计算,但是为简单起见,其他情况不考虑)。其他指标过高也说明MySQL状态不正常。这里为了简单起见,主要指的是%us过高的场景。MySQL和线程MySQL是单进程多线程结构,也就是说在独占的MySQL服务器中,用top命令只能看到一行数据。TOP命令效果这里可以看到MySQL的进程号。如果要查看线程状态,需要使用top-HTOP命令效果。在这里可以看到MySQL中每个线程的ID。可以看到MySQL启动后,会创建很多内部线程来工作。这些内部线程包括MySQL自身用于清洗、读写数据的系统线程,以及处理用户SQL的线程,姑且称之为用户线程。用户线程有一个特点:从程序端发送到MySQL端的SQL只会由一个用户线程执行(one-thread-per-connection),所以MySQL在处理复杂查询时,“一核难””、多核围观”的尴尬现象。参考%us的定义,对于Linux系统来说,MySQL进程及其启动的所有线程都不算作内核进程,所以当MySQL系统线程和用户线程繁忙时,会在CPU使用率。CPU什么时候达到100%?当CPU达到100%时,MySQL会做什么?从前面的分析来看,MySQL主要有两类线程占用CPU:系统线程和用户线程。所以在MySQL专用服务器上,只需要关注这两种线程的情况就可以覆盖大部分的问题场景。在实际环境中,系统线程遇到问题的次数较少。一般来说,多个系统线程很少会同时满负荷运行。只要服务器的可用核心数大于等于4,一般不会有问题Upto100%CPU,当然有些bug可能会有影响,比如这个:MySQLBUG比较少见,但是在日常的问题排查中,系统线程的问题也是需要注意的。用户线程提到用户线程很忙。很多时候肯定会根据经验在第一时间想到慢查询。确实90%以上的时间都是“慢查询”造成的,但是作为方法论,还是要根据分析下结论~参考us的定义,指的是CPU占用量timeocposedbyuserthreads,表示用户线程占用的时间很多。一方面是在进行长期的计算,比如:orderby,groupby,临时表,join等,这种问题可能是查询效率不高,导致单个sql语句占用CPU时间比较长,也可能是单纯的数据量比较大,导致计算量巨大。另一方面,单纯的QPS压力大,所以CPU时间用完了。比如4核服务器,支持20k到30k点查询。每个SQL占用的CPU时间不多,但是因为整体QPS高,所以CPU时间是占的。问题定位分析完成后,开始实战。基于前面的分析,这里给出一些经典的CPU100%场景,并给出一个简单的定位方法作为参考。PS:系统线程bug的场景跳过,以后会作为一个详细的案例来分析。CPU100%慢查询问题出现后,真正的慢查询和100%CPU影响的正常查询会混在一起。很难直观地查看进程列表或慢日志来找到罪魁祸首。这个时候就需要一些更清晰的查询。特征进行识别。从上面的简单分析可以看出,查询效率低的慢查询通常有以下几种情况:全表扫描:Handler_read_rnd_next的值会急剧增加,slowlog中row_examined的值也会针对此类查询很高。高的。索引效率不高,索引选错:Handler_read_next的值会突然增大,但需要注意的是,这种情况也可能是业务量突然增大导致的,需要结合查看QPS/TPS。在slowlog中查找此类查询会很麻烦。row_examined的值通常在故障前后不同,或者高得不合理。比如在数据倾斜的场景下,如果范围很小的范围查询,某个范围的row_examined非常高,而其他范围的row_examined都比较低,那么索引可能效率不高。排序有很多种:orderby、groupby等查询通常不容易直接从Handler的指标判断。如果没有索引或者索引不好,导致排序操作没有被淘汰,通常可以看到这种在processlist和slowlog类的查询语句出现较多。当然,如果不想详细分析MySQL指标或者情况比较紧急,可以直接在slowlog中使用rows_sent和row_examined做简单的划分。例如,row_examined/rows_sent>1000可以作为“嫌疑人”取出。这类问题一般可以通过优化索引来解决。PS:1000只是一个经验值,要根据实际业务情况来定。计算量大的问题通常是由于数据量大。即使索引没有问题,执行计划没问题,也会造成CPU100%,结合MySQLone-thread-per-connection的特点,不需要太多的并发就可以完全跑起来CPU使用率。这种查询其实更容易查,因为执行时间一般比较长,在processlist中会很显眼,但在slowlog中可能查不到,因为没有执行的语句不会被记录.一般来说,这类问题常见的解决方案有以下三种:读写分离,将这类查询放到业务中不经常使用的只读从库中。在程序段拆分SQL,将单个大查询拆分成多个小查询。使用HBASE、Spark等OLAP方案支持。QPS高等问题简直就是硬件资源的瓶颈。不管是row_examined/rows_sent的比值,SQL索引,执行计划,还是SQL计算,都不会出现明显的问题,但是QPS指标会比较高,processlist里面可能什么都看不到,例如:processlist总结其实CPU100%的问题不仅仅是简单的%us,还有%io、%sys等,其中会涉及到MySQL和Linux链接的一部分内容,会更加展开。本文只是试图从%us的角度梳理排查定位的思路和方法。在分析%io、%sys等问题时,也可以采用类似的思路。从这些指标的含义出发,结合MySQL的一些特性或Features,逐步了解出现背后的原因。
