linux性能分析篇之cpu、io

1. 工具介绍

vmstat

选用vmstat原因:大多数的发行版基本都有此命令,但是procinfo,pidstat,mpstat等命令是没有的。

[root@cubblestone ~]# vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 500488 153152 1139216 0 0 1 215 3 3 1 1 98 1 0
0 0 0 500488 153152 1139220 0 0 0 128 761 1290 0 1 99 0 0
0 0 0 500504 153152 1139220 0 0 0 0 693 1206 0 0 100 0 0
  1. procs
    r 当前可运行的进程数。也就是已经加入了运行队列,即已经分配了CPU,但是并没有在等待IO。(所以数量超过了cpu的个数,那么cpu会有瓶颈)
    b 等待IO完成的被阻塞的进程数。
  2. memory
    swpd 虚拟内存已使用的大小,表示当前已使用的交换页面大小。如果该值较高,表示系统当前的物理内存不足,导致系统频繁进行页面交换。这可能会导致系统性能下降,因为磁盘操作相对于内存访问速度较慢。
    free 未被OS或者程序使用的物理内存。
    buff 字段表示当前已分配给缓冲的大小(单位KB)。较高的 buff 值通常是好的,因为它表示系统正在有效地使用缓冲区来提高文件系统的性能。当系统需要读取或写入文件时,可以从缓冲中获取数据,而无需直接访问磁盘,从而加快访问速度。
    cache 用于保存之前从硬盘读取的数据的系统告诉缓存或者内存大小(单位KB)。如果应用程序再次需要该数据,内核可以从内存而非硬盘抓取数据,提高性能。
  3. swap
    si 每秒从磁盘读入虚拟内存的大小(单位KB/s),如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉。
    so 每秒虚拟内存写入磁盘的大小(单位KB/s),如果这个值大于0,同上。
    注:swap被我关掉了,所以si和so为0。
  4. io
    bi Blocks received from a block device (blocks/s), 每秒从块设备接收到的块数,单位:块/秒 也就是读磁盘。
    bo Blocks sent to a block device (blocks/s), 每秒发送到块设备的块数,单位:块/秒 也就是写磁盘。
  5. system
    in 每秒CPU的中断次数,包括时间中断
    cs 每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目。
  6. cpu
    us 用户CPU时间。
    sy 系统CPU时间。
    id 空闲 CPU时间,一般来说,id + us + sy = 100。
    wa 等待IO CPU时间。

2. 做实验

2.1 起一个进程

本次实验,起一个dd进程,往磁盘写数据,为防止磁盘满,写个while循环清空磁盘。

[root@cubblestone ~]# dd if=/dev/zero of=/opt/file.txt bs=1M count=10000000000 &
[1] 23032
[root@cubblestone ~]#
[root@cubblestone ~]# while true;do sleep 1; echo "" >/opt/file.txt ;done &
[1] 22536
[root@cubblestone ~]#

2.2 持续观察vmstat输出结果(命令是每隔1秒输出一次,并且持续输出的,分析部分内容即可)

[root@cubblestone ~]# 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
 4 0 0 1091492 20292 675056 0 0 1 219 3 3 1 1 98 1 0
 0 1 0 1248084 20292 517664 0 0 0 154728 1444 1980 1 16 18 66 0
 1 1 0 962176 20292 803552 0 0 0 174600 2266 2548 1 18 41 41 0
 1 1 0 1274380 20292 491332 0 0 0 105992 1647 2322 0 11 18 71 0
 0 2 0 925148 20304 841484 0 0 0 199836 2035 2364 1 18 33 48 0
 0 1 0 1299008 20304 466952 0 0 0 80912 2554 7343 1 10 25 64 0
 0 2 0 893668 20304 871752 0 0 0 225740 2150 2759 2 21 31 47 0
 2 3 0 1324848 20304 439260 0 0 0 52832 2165 2765 1 13 17 70 0
 0 2 0 861524 20400 904692 0 0 0 255576 2125 3304 1 21 21 57 0
 1 0 0 1269596 20400 496764 0 0 0 23092 2235 2744 0 14 40 46 0
 1 0 0 1074792 20400 691200 0 0 0 273936 1479 1950 1 23 24 53 0
 1 1 0 983796 20404 780544 0 0 20 160248 2575 3037 3 22 42 34 0
 0 1 0 1256388 20404 507432 0 0 0 121380 2185 5755 1 11 16 72 0
 2 1 0 941968 20412 822788 0 0 0 180944 2064 2348 1 16 35 48 0
 0 1 0 1285236 20412 478680 0 0 0 97804 1873 4189 1 9 26 64 0
 0 2 0 905644 20412 858736 0 0 0 215472 1979 2225 1 18 35 46 0
 0 1 0 1309372 20412 454588 0 0 0 68196 2231 4951 1 10 31 57 0
 0 3 0 875620 20412 888492 0 0 0 239008 2422 3655 1 19 26 54 0
 0 5 0 1335960 20412 428052 0 0 0 41620 2186 2654 1 7 24 68 0
 0 2 0 848184 20516 916284 0 0 0 262316 2038 2771 3 20 14 63 0
 1 0 0 1236948 20516 527692 0 0 0 23112 2313 2608 1 11 45 44 0
 1 0 0 1146916 20516 616888 0 0 0 279528 1967 3978 1 21 15 64 0
 1 1 0 993188 20516 772152 0 0 0 157652 3020 3914 1 18 45 36 0
 0 1 0 1261300 20516 503236 0 0 0 118852 1549 2300 1 14 14 71 0

IO和CPU分析

让我们来关注下相关字段bi、bo、in、cs、us、sy、id、wa。

  1. 从bi、bo字段,我们可以看出,由进程在疯狂向磁盘写数据,而没什么读数据的动作。忽略第一行,写的速率在大概在80000(块/秒)~ 260000(块/秒),我的磁盘为/dev/vda1,所以块的大小如下

    [root@cubblestone ~]# tune2fs -l /dev/vda1 | grep "Block size"
    Block size: 4096
    [root@cubblestone ~]#
  2. 4096字节也就是2KB。那么也就能计算出写速率了,大概在156(MB/s) ~ 508(MB/s)。所以为什么能看出有进程在疯狂的写数据。
  3. 结合b字段可以看出,时不时有数个进程在等待IO完成。
  4. 再结合CPU部分,us和sy都比较小,代表用户态和内核态消耗的CPU不大,而wa的占比很高(在30%~70%),代表CPU消耗在IO上的时间很长,也能说明有进程在疯狂IO。(注:us+sy+id+wa+st = 100)
    但是这样并不能说明进程就达到了瓶颈,万一人家磁盘就是好,能够支持的写速率就是很高呢,让我们来想看下磁盘情况。

iostat

需要安装iostat

yum install sysstat -y

命令说明:1秒钟输出一次结果,输出3次。(分析真正的结果需要忽略第一次的输出,命令特性,vmstat也一样。)

[root@cubblestone yum.repos.d]# iostat -x 1 3
Linux 3.10.0-1160.71.1.el7.x86_64 (cubblestone) 06/04/2023 _x86_64_ (2 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
 0.83 0.00 0.77 0.58 0.00 97.81
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 8.17 0.05 9.28 1.60 486.01 104.52 0.72 77.28 19.63 77.60 1.25 1.16
scd0 0.00 0.00 0.00 0.00 0.10 0.00 120.62 0.00 0.51 0.51 0.00 0.42 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
 0.00 0.00 18.69 37.37 0.00 43.94
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 4.00 0.00 326.00 0.00 109648.00 672.69 174.38 534.91 0.00 534.91 2.58 84.20
scd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
 0.52 0.00 7.73 63.92 0.00 27.84
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 0.00 0.00 231.00 0.00 110028.00 952.62 155.38 672.66 0.00 672.66 4.33 100.00
scd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
[root@cubblestone yum.repos.d]#

命令字段解释
avg-cpu 行:统计了CPU的平均使用率,可以看出iowait达到了30~60,跟vmstat的wa字段是一个意思。
下面才是分析磁盘的字段。

  • rrqm/s 在提交给磁盘前,每秒被合并的读请求的数量。
  • wrqm/s 在提交给磁盘前,每秒被合并的写请求的数量。
  • r/s 每秒读取的io次数。
  • w/s 每秒写入的io次数。
  • rMB/s 表示每秒读取的数据量,单位为MB。
  • wMB/s 表示每秒写入的数据量,单位为MB。
  • avgrq-sz 表示平均每个I/O请求的扇区数,单位为扇区。
  • avgqu-sz 表示平均每个设备队列中的请求数量,单位为请求数量。
  • await 表示请求的平均消耗的时间,单位为毫秒。
  • r_await 表示读请求的平均等待时间,单位为毫秒。
  • w_await 表示写请求的平均等待时间,单位为毫秒。
  • svctm 表示平均每个I/O请求的服务时间,单位为毫秒。
  • %util 表示设备的利用率百分比,没有具体的单位。

想看有没瓶颈,着重关注如下几个字段
awaitr_awaitw_awaitsvctm
await:其代表的是IO请求,从加入IO队列开始到其真正处理完数据,平均消耗的时间,也就是【等待+处理】的时间。
r_await、w_await:跟await含义一样,只是从await中拆分出来读和写的情况。
svctm: 表示的是IO请求从开始处理到处理完毕消耗的平均时间,也就是【处理】的时间。

以上面的命令最后一次输出的结果为例:
vda磁盘的await达到了672.66ms,而svctm只有4.33ms,从他俩的差距可以看出,时间都耗在了等待IO上面。

那是什么进程在产生大量的IO呢?

iotop

[root@cubblestone ~]# iotop -oP

由下图显而易见:

总结

从上面的vmstat到下面的iostat我们可以得出如下结论:

vmstat可以看到有产生大量IO的进程,IO占用CPU在30%~70%,然后我们排查是哪个磁盘在进行IO。

iostat可以看出是vda在进行大量的IO,并且await已经远远大于svctm,所以IO达到了瓶颈。
然后通过iotop排查出是我们的dd进程在疯狂写数据到vda磁盘。

作者:蓝色瞳仁原文地址:https://segmentfault.com/a/1190000043862906

%s 个评论

要回复文章请先登录注册