系统的平均负载
可以通过uptime命令查看系统的平均负载: (top命令可以也可以,不过显示信息更多)
$ uptime
10:35:08 up 23 days, 19:29, 3 users, load average: 0.11, 0.07, 0.06
执行uptime命令,可以看到 当前时间、系统运行时间以及正在登录用户数。后面是过去 1 分钟、5 分钟、15 分钟的平均负载。
通过man uptime看一下到底什么是平均负载:
也就是说,平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数。
1、可运行状态:使用CPU或者正在等待使用CPU的进程所处的状态
2、不可中断状态:进程在等待硬件设备IO等时的状态,这些进程不可打断,用kill也不能消灭。 ps状态下是D状态的进程。当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。也就是说这是一种保护机制。 (当一个机器的D状态进程较多,通常是有一些问题的)
因此,想通过平均负载来看系统的繁忙情况,需要知道自己的系统有多少个CPU 【可以通过top或者查看/proc/cpuinfo查看】。如果是单CPU并且平均负载是1,这说明CPU一直被占用。如果是4CPU的机器平均负载是1的话,说明CPU的75%是空闲的。如果是单CPU平均负载是4,那么说明大部分进程都是在竞争CPU并且竞争不到的。
一般当平均负载高于CPU数量的0.7时,就说明可能是存在问题导致高负载了,高于1的话就需要找一下问题修复了,如果更高的话可能导致响应慢等情况了。
一般来说CPU的使用率和平均负载的关系如下:
- 对于CPU 密集型进程,会单位时间使用大量 CPU ,因此平均负载会较大,这种情况二者是较为一致的
- 对于IO密集型进程,大部分时间都在等待IO,因此平均负载也会比较大,但是CPU使用率是比较低的
需要C/C++ Linux服务器架构师学习资料私信“资料”(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
案例分析
工具:stress (系统压力测试工具)和sysstat (监控分析系统性能的工具) 下载方法:用yum install 即可 或者 apt-get install
环境:Xshell连接的Linux远程主机,版本3.10
需要开启多个终端,部分终端用于运行监测程序,部分终端用来运行实例模拟高负载 【虚拟机图形界面的话可以创建多个命令行即可,远程Linux则建立多个连接窗口即可】
可以看一下man stress,可以模拟多种系统压力施加
模拟高CPU密集的进程
stress -c 4 #运行4个高CPU进程
在一个终端运行stress,另外的终端用于监视系统负载以及其他性能
top监视的情况:
[root@jessy ~]# top
top - 14:33:58 up 23 days, 23:28, 4 users, load average: 4.28, 1.42, 0.54
Tasks: 118 total, 6 running, 111 sleeping, 1 stopped, 0 zombie
%Cpu(s): 99.7 us, 0.2 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem : 8008684 total, 5493028 free, 195948 used, 2319708 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 7506152 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
可以看到平均负载逐步上升接近到4,并且可以看到有4个CPU使用率接近100%的进程,平均CPU使用率几乎达到100%,几乎所有的时间都在用户态
mpstat监视情况:
[root@jessy ~]# mpstat -P ALL 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (jessy) 07/22/2020 _x86_64_ (4 CPU)
02:32:47 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
02:32:52 PM all 99.74 0.00 0.19 0.00 0.00 0.06 0.00 0.00 0.00 0.00
02:32:52 PM 0 99.44 0.00 0.28 0.00 0.00 0.28 0.00 0.00 0.00 0.00
02:32:52 PM 1 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
02:32:52 PM 2 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
02:32:52 PM 3 99.42 0.00 0.29 0.00 0.00 0.29 0.00 0.00 0.00 0.00
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 99.74 0.00 0.19 0.00 0.00 0.06 0.00 0.00 0.00 0.00
Average: 0 99.44 0.00 0.28 0.00 0.00 0.28 0.00 0.00 0.00 0.00
Average: 1 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: 2 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: 3 99.42 0.00 0.29 0.00 0.00 0.29 0.00 0.00 0.00 0.00
mpstst可以看到每个cpu 的情况,可知每个CPU都有接近100%的使用率
pidstat监视的情况:
[root@jessy ~]# pidstat 1 1
Linux 3.10.0-1062.18.1.el7.x86_64 (jessy) 07/22/2020 _x86_64_ (4 CPU)
02:37:07 PM UID PID %usr %system %guest %CPU CPU Command
02:37:08 PM 0 3126 99.01 0.00 0.00 99.01 1 stress
02:37:08 PM 0 3127 100.00 0.00 0.00 100.00 2 stress
02:37:08 PM 0 3128 98.02 0.00 0.00 98.02 3 stress
02:37:08 PM 0 3129 99.01 0.00 0.00 99.01 0 stress
02:37:08 PM UID PID %usr %system %guest %CPU CPU Command
02:37:09 PM 0 3126 99.01 0.00 0.00 99.01 1 stress
02:37:09 PM 0 3127 98.02 0.00 0.00 98.02 2 stress
02:37:09 PM 0 3128 100.00 0.00 0.00 100.00 3 stress
02:37:09 PM 0 3129 99.01 0.00 0.00 99.01 0 stress
02:37:09 PM 0 3608 0.99 0.00 0.00 0.99 0 barad_agent
02:37:09 PM 0 4242 0.00 0.99 0.00 0.99 1 pidstat
可以看到CPU被跑的满满的,并且可以看到是哪些进程在占据CPU
通过top和pidstat都可以找到到底是哪些进程在使CPU繁忙,因此找到根源后便可以去找更细的原因。
模拟IO密集型的进程
stress -i 3 #运行3个高IO进程
在一个终端运行stress,另外的终端用于监视系统负载以及其他性能
top监视的情况:
[root@jessy ~]# top
top - 11:37:16 up 23 days, 20:31, 4 users, load average: 3.00, 3.21, 2.85
Tasks: 108 total, 3 running, 104 sleeping, 1 stopped, 0 zombie
%Cpu(s): 0.2 us, 49.0 sy, 0.0 ni, 49.9 id, 0.9 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8008684 total, 5492672 free, 187984 used, 2328028 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 7514116 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
可以看到系统负载接近3,但是CPU利用率并没有那么高,并且可以看到 D 状态 (不可中断状态)
mpstat监视的情况:
[root@jessy ~]# mpstat -P ALL 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (jessy) 07/22/2020 _x86_64_(4 CPU)
11:31:29 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
11:31:34 AM all 0.05 0.00 52.10 1.05 0.00 0.00 0.00 0.00 0.00 46.79
11:31:34 AM 0 0.00 0.00 96.01 2.00 0.00 0.00 0.00 0.00 0.00 2.00
11:31:34 AM 1 0.20 0.00 39.40 1.00 0.00 0.00 0.00 0.00 0.00 59.40
11:31:34 AM 2 0.20 0.00 41.20 0.80 0.00 0.00 0.00 0.00 0.00 57.80
11:31:34 AM 3 0.20 0.00 31.34 0.60 0.00 0.00 0.00 0.00 0.00 67.86
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.05 0.00 52.10 1.05 0.00 0.00 0.00 0.00 0.00 46.79
Average: 0 0.00 0.00 96.01 2.00 0.00 0.00 0.00 0.00 0.00 2.00
Average: 1 0.20 0.00 39.40 1.00 0.00 0.00 0.00 0.00 0.00 59.40
Average: 2 0.20 0.00 41.20 0.80 0.00 0.00 0.00 0.00 0.00 57.80
Average: 3 0.20 0.00 31.34 0.60 0.00 0.00 0.00 0.00 0.00 67.86
可以看到iowait值非常高,说明IO才是当前系统负载高的主要原因,同时可以看到主要事件消耗在于系统调用上,因为IO是需要系统调用的,用户态几乎不占时间。
pidstat查看相关状态:
[root@jessy ~]# pidstat 1 1
Linux 3.10.0-1062.18.1.el7.x86_64 (jessy) 07/22/2020 _x86_64_(4 CPU)
02:39:56 PM UID PID %usr %system %guest %CPU CPU Command
02:39:57 PM 0 4719 0.00 61.00 0.00 61.00 0 stress
02:39:57 PM 0 4720 0.00 81.00 0.00 81.00 1 stress
02:39:57 PM 0 4721 0.00 50.00 0.00 50.00 2 stress
02:39:57 PM 0 4926 0.00 1.00 0.00 1.00 3 pidstat
02:39:57 PM UID PID %usr %system %guest %CPU CPU Command
02:39:58 PM 0 4719 0.00 59.00 0.00 59.00 0 stress
02:39:58 PM 0 4720 0.00 42.00 0.00 42.00 3 stress
02:39:58 PM 0 4721 0.00 94.00 0.00 94.00 2 stress
02:39:58 PM 0 32473 0.00 1.00 0.00 1.00 3 YDService
可以看到具体的进程占据CPU和IO的情况
通过top或者pidstat可以找到具体是哪个进程在频繁IO,从而定位问题原因
上下文切换
Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行,这是通过频繁的上下文切换、将CPU轮流分配给不同任务从而实现的。
每个进程运行时,CPU都需要知道进程已经运行到了哪里以及当前的各种状态,因此系统事先设置好 CPU 寄存器和程序计数器。CPU 上下文切换,就是先把前一个任务的 CPU 上下文(CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务,而保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。
进程上下文切换是消耗时间的,平均下文切换都需要几十纳秒到数微秒的 CPU 时间,因此如果进程上下文切换次数过多,就会导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间,实际上有效的CPU运行时间大大减少(可以认为上下文切换对用户来说是在做无用功)
上下文切换的时机:
- 根据调度策略,将CPU时间划片为对应的时间片,当时间片耗尽,就需要进行上下文切换
- 进程在系统资源不足,会在获取到足够资源之前进程挂起
- 进程通过sleep函数将自己挂起
- 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行,也就是被抢占
- 当发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序
现代操作系统中,线程是调度的基本单位,而进程则是资源拥有的基本单位,因此也会发生线程切换。如果是同一进程内的线程切换,由于大部分资源是共享的,因此不需要保存,只保存寄存器等不共享数据,因此这时候的线程切换是更轻量级更快的。如果不是同意进程内的线程切换,就等于进程切换了,花销稍大。
查看上下文切换:
vmstat命令可以看到系统整体的context switches次数:
[root@jessy ~]# vmstat 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
3 0 0 5492032 220452 2105940 0 0 0 5 2 1 0 0 100 0 0
3 0 0 5492412 220452 2105952 0 0 0 369 3267 2204 0 50 48 2 0
2 0 0 5492340 220452 2105968 0 0 0 342 3427 2477 0 49 50 1 0
- cs:每秒上下文切换的次数
- in:每秒中断的次数
- r:就绪队列的长度,即正在运行和等待 CPU 的进程数。
- b:处于不可中断睡眠状态的进程数
可以通过pidstat查看每个进程的上下文切换情况:-w
[root@jessy ~]# pidstat -w
Linux 3.10.0-1062.18.1.el7.x86_64 (jessy) 07/22/2020 _x86_64_(4 CPU)
03:10:50 PM UID PID cswch/s nvcswch/s Command
03:10:50 PM 0 1 1.10 0.00 systemd
03:10:50 PM 0 2 0.00 0.00 kthreadd
03:10:50 PM 0 4 0.00 0.00 kworker/0:0H
03:10:50 PM 0 6 0.07 0.00 ksoftirqd/0
03:10:50 PM 0 7 0.34 0.00 migration/0
03:10:50 PM 0 8 0.00 0.00 rcu_bh
03:10:50 PM 0 9 14.76 0.00 rcu_sched
- cswch :表示每秒自愿上下文切换的次数 是指进程无法获取所需资源,导致的上下文切换
- nvcswch :表示每秒非自愿上下文切换的次数 指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换
案例分析
工具:sysbench(一个多线程的基准测试工具)和sysstat (监控分析系统性能的工具) 下载方法:用yum install 即可 或者 apt-get install
环境:Xshell连接的Linux远程主机,版本3.10
在第一个终端里运行 sysbench ,模拟系统多线程调度的瓶颈:
# 20个线程运行,模拟多线程切换的问题
$ sysbench --threads=20 threads run
在另一个终端用vmstat查看系统的上下文切换次数:
[root@jessy ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
5 0 0 5483872 220568 2114760 0 0 0 5 3 2 0 0 100 0 0
5 0 0 5483788 220568 2114760 0 0 0 0 24004 733269 35 56 9 0 0
5 0 0 5483804 220568 2114760 0 0 0 80 33083 688786 33 55 12 0 0
5 0 0 5483828 220568 2114760 0 0 0 0 21859 760155 32 58 9 0 0
6 0 0 5483912 220568 2114764 0 0 0 0 31601 794251 33 55 12 0 0
5 0 0 5483912 220568 2114764 0 0 0 0 22575 671252 35 56 9 0 0
可以看到每秒的上下文切换次数达到了70万次左右,这一定会大大影响系统性能,就绪队列中的进程数量也明显提升,已经高于CPU数量了,us和sy使用率较高,加起来在接近100%,同时in的数量非常高,说明每秒的中断次数非常高
用pidstat查看具体的情况, (-t可以显示出更具体的线程切换次数)
[root@jessy ~]# pidstat -wt -u 1
Linux 3.10.0-1062.18.1.el7.x86_64 (jessy) 07/22/2020 _x86_64_(4 CPU)
03:41:38 PM UID TGID TID %usr %system %guest %CPU CPU Command
03:41:39 PM 0 3612 - 0.98 0.00 0.00 0.98 2 barad_agent
03:41:39 PM 0 18524 - 100.00 100.00 0.00 100.00 2 sysbench
03:41:39 PM 0 - 18530 3.92 8.82 0.00 12.75 3 |__sysbench
03:41:39 PM 0 - 18531 7.84 12.75 0.00 20.59 0 |__sysbench
03:41:39 PM 0 - 18532 7.84 11.76 0.00 19.61 0 |__sysbench
....
03:41:38 PM UID TGID TID cswch/s nvcswch/s Command
03:41:39 PM 0 1 - 0.98 0.00 systemd
03:41:39 PM 0 - 18539 10184.31 38460.78 |__sysbench
03:41:39 PM 0 - 18540 9807.84 31880.39 |__sysbench
03:41:39 PM 0 - 18541 8456.86 23916.67 |__sysbench
03:41:39 PM 0 - 18542 8710.78 25382.35 |__sysbench
03:41:39 PM 0 - 18543 9375.49 29080.39 |__sysbench
03:41:39 PM 0 - 18544 11208.82 31827.45 |__sysbench
03:41:39 PM 0 18555 - 0.98 1.96 pidstat
...
可以看到sysbench的系统CPU占用率达到了100%,并且几乎占据了所有的usr和sys时间。也能看到sysbench的进程中存在这大量的自愿上下文切换和非自愿上下文切换
查看中断情况:
watch -d cat /proc/interrupts
可以看到LOC和RES值非常高,LOC是计时器中断,RES是Rescheduling interrupts,也就是调度中断,因此可以基本确定,中断的产生主要是因为频繁的调度,也就是任务过多引起过多上下文切换导致的。
不可中断进程过多
僵尸进程,表示进程已经退出,但它的父进程还没有回收子进程占用的资源。正常情况下,当一个进程创建了子进程后,它应该通过系统调用 wait() 或者 waitpid() 等待子进程结束,回收子进程的资源。通常来说,僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡;或者在父进程退出后,由 init 进程回收后也会消亡。但是如果父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态。大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建,所以这种情况一定要避免。
不可中断状态,表示进程正在跟硬件交互,为了保护进程数据和硬件的一致性,系统不允许其他进程或中断打断这个进程。当 iowait 升高时,进程很可能因为得不到硬件的响应,而长时间处于不可中断状态。进程长时间处于不可中断状态,通常表示系统有 I/O 性能问题。
通常可以用top命令和ps命令查看系统的进程状态:
[root@VM-238-167-centos /]# top
top - 11:43:46 up 19:21, 2 users, load average: 81.48, 35.56, 13.78
Tasks: 258 total, 2 running, 253 sleeping, 1 stopped, 2 zombie
%Cpu(s): 0.2 us, 0.3 sy, 0.0 ni, 34.6 id, 64.8 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16165976 total, 8499940 free, 6695244 used, 970792 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 9338500 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 32016 root 20 0 7076 6232 808 R 1.0 0.0 3:35.52 sap1002
26849 root 20 0 70040 65528 44 D 0.3 0.4 0:00.02 app
17626 root 20 0 0 0 0 S 0.3 0.0 0:00.06 kworker/6:2 32018 root 20 0 23336 8680 1164 S 0.3 0.1 0:21.21 sap1004 32031 root 20 0 45228 26664 5832 S 0.3 0.2 1:16.57 sap1009 1 root 20 0 53128 4336 2488 S 0.0 0.0 0:08.35 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
可以看到S即为进程状态,包括R:运行状态 S:Sleep状态 D:不可中断状态
案例分析:【该实验有可能直接导致死机,因为负载会达到非常高的地步,故根据设备配置实验】
docker镜像:
运行了镜像实例,这是一个高IO的实例,运行这个docker程序后可以看到:
[root@VM-238-167-centos /]# ps aux | grep /app
root 26564 0.0 0.0 4500 564 pts/0 Ss+ 11:39 0:00 /app -d /dev/vdb1
root 26622 0.0 0.4 70040 65528 pts/0 D+ 11:39 0:00 /app -d /dev/vdb1
root 26623 0.0 0.4 70040 65528 pts/0 D+ 11:39 0:00 /app -d /dev/vdb1
root 26629 0.0 0.4 70040 65528 pts/0 D+ 11:39 0:00 /app -d /dev/vdb1
root 26630 0.0 0.4 70040 65528 pts/0 D+ 11:39 0:00 /app -d /dev/vdb1
....
[root@VM-238-167-centos /]# top
top - 11:43:46 up 19:21, 2 users, load average: 81.48, 35.56, 13.78
Tasks: 258 total, 2 running, 253 sleeping, 1 stopped, 2 zombie
%Cpu(s): 0.2 us, 0.3 sy, 0.0 ni, 34.6 id, 64.8 wa, 0.0 hi, 0.0 si, 0.0 st
查看top可以知道平均负载极高!但是CPU利用率很低,io使用率很高,说明大概率是因为IO导致了如此高的系统负载。
在终端中运行 dstat 命令,观察 CPU 和 I/O 的使用情况:
[root@VM-238-167-centos /]# dstat 1 10
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send| in out | int csw
0 0 100 0 0 0| 682k 48k| 0 0 | 0 0 | 797 808
0 0 68 32 0 0| 130M 20k| 54B 146B| 0 0 |1040 827
0 0 75 25 0 0| 130M 0 | 96B 860B| 0 0 |1022 789
0 0 75 25 0 0| 130M 0 | 331B 894B| 0 0 |1071 856
0 0 72 28 0 0| 130M 24k| 54B 42B| 0 0 |1057 823
0 0 63 37 0 0| 130M 0 | 146B 388B| 0 0 |1036 789
0 0 63 37 0 0| 130M 0 | 96B 700B| 0 0 |1043 798
0 0 62 37 0 0| 130M 932k| 54B 42B| 0 0 |1033 797
0 0 62 37 0 0| 130M 0 | 96B 388B| 0 0 |1033 798
0 0 67 33 0 0| 130M 20k|1064B 7858B| 0 0 |1054 843
1 0 62 37 0 0| 130M 0 | 54B 42B| 0 0 |1074 789
可以看到 iowait 升高(wai)时,磁盘的读请求(read)都会很大。这说明 iowait 的升高跟磁盘的读请求有关,很可能就是磁盘读导致的。
因此就需要找一些是哪些进程在频繁read,用top查找:
[root@VM-238-167-centos /]# top
top - 14:44:34 up 2:45, 2 users, load average: 43.34, 15.43, 5.63
Tasks: 212 total, 1 running, 209 sleeping, 0 stopped, 2 zombie
%Cpu(s): 0.0 us, 0.2 sy, 0.0 ni, 59.0 id, 40.8 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16165976 total, 11210260 free, 4318284 used, 637432 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 11722680 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1160 root 20 0 70040 65524 44 D 0.3 0.4 0:00.01 app 1166 root 20 0 70040 65524 44 D 0.3 0.4 0:00.01 app 1315 root 20 0 70040 65524 44 D 0.3 0.4 0:00.01 app 7852 root 20 0 38008 19720 1168 S 0.3 0.1 0:02.06 secu-tcs-agent 9365 root 20 0 7208 6288 804 S 0.3 0.0 0:26.86 sap1002 9381 root 20 0 22612 4276 3700 S 0.3 0.0 0:04.14 sap1007
可以看到CPU负载非常高,但是CPU使用率几乎为0,而有着大量的iowait,并且看到有很多D进程状态,D进程状态是不可中断状态,因此大概率就是这些进程在占据磁盘读,具体去找这些查看查看。
因为top看到1160处于D状态,因此查看是否是该进程的原因:
[root@VM-238-167-centos /]# pidstat -d -p 1160 1 3
Linux 3.10.107-1-tlinux2_kvm_guest-0049 (VM-238-167-centos) 07/23/20 _x86_64_(8 CPU)
14:48:42 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
14:48:43 0 1160 0.00 0.00 0.00 app
14:48:44 0 1160 0.00 0.00 0.00 app
14:48:45 0 1160 0.00 0.00 0.00 app
Average: 0 1160 0.00 0.00 0.00 app
显然,并不是,因为读写都是0。同理发现其他几个也是这样的情况。
索性直接pidstat查看所有的进程情况来分析:
[root@VM-238-167-centos /]# pidstat -d 1 5
Linux 3.10.107-1-tlinux2_kvm_guest-0049 (VM-238-167-centos) 07/23/20 _x86_64_(8 CPU)
14:54:33 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
14:54:34 0 3204 503.50 0.00 0.00 app
14:54:34 0 3216 520.50 0.00 0.00 app
14:54:34 0 3331 16128.00 0.00 0.00 app
14:54:34 0 3332 1024.00 0.00 0.00 app
14:54:34 0 3337 16128.00 0.00 0.00 app
14:54:34 0 3338 16128.00 0.00 0.00 app
14:54:34 0 3344 16128.00 0.00 0.00 app
14:54:34 0 3349 16128.00 0.00 0.00 app
14:54:34 0 3356 16128.00 0.00 0.00 app
14:54:34 0 3357 16128.00 0.00 0.00 app
14:54:34 0 3364 16128.00 0.00 0.00 app
14:54:34 0 3365 16128.00 0.00 0.00 app
发现确实是app进程在运行,并且占据了非常大的read。
用strace看一下3204进程的系统调用情况:
[root@VM-238-167-centos /]# strace -p 3204
strace: attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted
显示没有权限,很不科学,已经是root了,那么看一下这个进程的状态:
[root@VM-238-167-centos /]# ps aux | grep 3204
root 3204 0.0 0.0 0 0 pts/0 Z+ 14:53 0:00 [app] <defunct>
发现变成了僵尸状态。
用perf top分析问题所在,找到app后进入其中看看,展开调用栈分析
看出进程在在通过系统调用 sys_read() 读取数据。并且从 new_sync_read 和 blkdev_direct_IO 能看出,进程正在对磁盘进行直接读,也就是绕过了系统缓存,每个读请求都会从磁盘直接读。
然后分析源码,发现
open(disk, O_RDONLY|O_DIRECT|O_LARGEFILE, 0755)
O_DIRECT,直接读写磁盘,删掉该选项。然后运行发现iowait非常低,该问题找到并解决。
这个例子中磁盘 I/O 导致了 iowait 升高,不过, iowait 高不一定代表 I/O 有性能瓶颈。当系统中只有 I/O 类型的进程在运行时,iowait 也会很高,但实际上,磁盘的读写远没有达到性能瓶颈的程度。因此,碰到 iowait 升高时,需要先用 dstat、pidstat 等工具,确认是不是磁盘 I/O 的问题,然后再找是哪些进程导致了 I/O。等待 I/O 的进程一般是不可中断状态,所以用 ps 命令找到的 D 状态(即不可中断状态)的进程,多为可疑进程。然后用strace分析,或者用 perf 工具,来分析系统的 CPU 时钟事件,找到问题的原因。