在Linux系统中,经常会因为负载过高导致各种性能问题。那么如何进行排查,其实是有迹可循,而且模式固定。
本次就来分享一下,CPU占用过高、磁盘IO占用过高的排查方法。
还是那句话,以最佳实践入手,真传一句话,假传万卷书。这就是工作中学习和读死书的区别与真相。
CPU占用率过高问题排查方法
使用mpstat查看cpu使用情况。
# mpstat 是一款 CPU 性能指标实时展示工具
# 能展示每个 CPU 核的资源视情况,同时还能将资源使用情况进行汇总展示
# 如果CPU0 的 %idle 已经为 0 ,说明此核已经非常繁忙
# 打印所有cpu核的情况(ALL),每隔1s打印一次,共打印5次
mpstat -P ALL 1 5
mpstat命令执行结果
从上面可以看到,服务器有 2 个 CPU(分别为0、1),每个 CPU 核的资源使用情况,也能很清晰的展示。
当服务器有特别多的 CPU 核,有时候看 CPU 汇总信息,发现 CPU 的 idle 很高,但是上面跑的应用程序却很慢,这个时候就需要看看每个核的资源试用情况了。
重点关注指标:
* %iowait:代表在监控的时间间隔内,等待硬盘 I/O 的时间,如果此值比较高,说明 IO 非常繁忙
* %idle:代表在监控的时间间隔内,CPU 闲置时间所占用的时间百分比,此值越大,代表 CPU 越空闲
2. 使用pidstat查看消耗cpu资源的进程。
# 参数-u表明监控cpu使用情况
# 参数2表示每隔2s输出一次,会循环输出
pidstat -u 2
Linux 3.10.0-957.el7.x86_64 (mysql) 12/30/2020 _x86_64_ (1 CPU)
04:57:41 PM UID PID %usr %system %guest %CPU CPU Command
04:57:43 PM 2001 10733 0.00 91.44 0.00 91.44 0 mysqld
04:57:43 PM 2001 12635 0.00 0.53 0.00 0.53 0 pidstat
从上面的结果可以看到,导致 CPU0 资源被耗尽的元凶是 mysqld 进程,占用91.44%,需要定位具体线程。
pidstat 是一个非常强大的性能指标监控工具,建议掌握,此工具可以用来监控全部或指定进程的 CPU、mem、线程,IO 的资源的使用情况。
# 参数-d表示监控进程对磁盘的使用情况pidstat -d 2
Linux 3.10.0-957.el7.x86_64 (mysql) 12/30/2020 _x86_64_ (1 CPU)
03:57:47 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
03:57:49 PM 2001 10733 139.13 0.00 0.00 mysqld
03:57:49 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
03:57:51 PM 2001 10733 34034.78 0.00 0.00 mysqld
可以查看指定进程的线程 CPU 资源使用情况。
# 参数 -t,可以获取指定进程的线程的 CPU 使用情况
pidstat -t 2 -p 10733
3. 使用 pidstat 查看消耗 CPU 资源的线程
pidstat -t 2 -p 10733
Linux 3.10.0-957.el7.x86_64 (mysql) 12/30/2020 _x86_64_ (1 CPU)
05:00:53 PM UID TGID TID %usr %system %guest %CPU CPU Command
05:00:55 PM 2001 10733 - 0.00 91.30 0.00 91.30 0 mysqld
05:00:55 PM 2001 - 10733 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10734 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10735 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10736 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10737 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10738 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10739 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10740 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10741 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10742 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10743 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10744 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10745 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10747 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10748 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10749 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10750 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10751 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10752 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10753 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10754 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10755 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10756 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10757 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10758 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10762 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10763 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10764 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10766 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10796 0.00 0.00 0.00 0.00 0 |__mysqld
05:00:55 PM 2001 - 10850 15.22 75.54 0.00 90.76 0 |__mysqld
可以很清楚看到是 10850 线程消耗了 CPU 资源,剩下的就根据操作系统的里线程 ID,去 MySQL 数据库里排查,此线程正在执行的操作。
4. MySQL中查询线程对应的具体SQL
-- 在 MySQL 5.7 版本,官方增加了一个视图,专门记录操作系统线程和数据库进程之间关联视图。
-- 前面定位的最消耗 IO 和 CPU 的线程 ID 为 10850:
select PROCESSLIST_ID,
THREAD_OS_ID,
PROCESSLIST_USER,
PROCESSLIST_HOST,
PROCESSLIST_DB,
PROCESSLIST_COMMAND,
PROCESSLIST_INFO
from performance_schema.threads
where THREAD_OS_ID=10850;
磁盘IO占用率过高排查方法
使用 iostat 查看磁盘 IO 的读写情况。
# 每隔1s输出一次
iostat -mxt 1
# 每隔1s输出一次,共输出2次
iostat -mxt 1 2
iostat命令输出
如果看到 %util 比较高,说明磁盘设备繁忙,需要定位到底是那个操作系统进程导致的大量读操作。
iostat 是一款用于监控系统设备的 IO 负载情况的工具,在运维工作中会被高频使用的工具之一。
# 常用参数介绍
* -m:输出结果以兆为单位显示
* -t:输出结果中显示时间戳
* -x:显示和 IO 相关的扩展数据,包括每个设备的读写、合并读、合并写、读写等待情况
# 输出指标介绍
* rrqm/s:每秒合并读的条目
* wrqm/s:每秒合并写的条目
* r/s:每秒 read I/O 设备次数
* w/s:每秒 write I/O 设备次数
* rMB/s: 每秒读取 M 字节数
* wMB/s:每秒写 M 字节数
* avgrq-sz:每次设备 I/O 操作平均数据大小
* avgqu-sz:I/O 队列平均长度
* await:每次设备 I/O 操作的平均等待时间,单位毫秒
* r_await:每次读 I/O 操作的平均等待时间,单位毫秒
* w_await:每次写 I/O 操作的平均等待时间,单位毫秒
* svctm:每次设备 I/O 操作的平均服务时间,单位毫秒
* %util:每秒中有百分之多少的时间用于 I/O 操作,此值越高,代表着磁盘越繁忙
2. 使用 iotop 定位最消耗 IO 资源的元凶
iotop -p 10733
可以看到10850 线程大量读操作,导致 IO 资源被消耗殆尽。
iotop 是一款用于监视磁盘设备 I/O 使用状况的工具,可监测到具体的线程使用的磁盘 IO 的信息,功能也是非常强大,可惜需要 root 权限,普通用户没有执行权限,所以一般会用 pidstat 工具来替代。
参数介绍:
-P:只显示进程 IO 读写情况
-p:监控指定进程的 IO 读写情况
-u:指定用户进程的 IO 读写情况
1. 查看指定用户的的进程
iotop -u mysql -P
2. 查看指定用户的进程和线程 IO 读写情况
iotop -u mysql
3. 查看指定进程的线程 IO 读写情况
iotop -p 10733
3. 根据线程定位具体SQL。
select PROCESSLIST_ID,
THREAD_OS_ID,
PROCESSLIST_USER,
PROCESSLIST_HOST,
PROCESSLIST_DB,
PROCESSLIST_COMMAND,
PROCESSLIST_INFO
from performance_schema.threads
where THREAD_OS_ID=10850;