linux性能分析工具

sysstat

sysstat是一个linux性能工具,用来监控和分析系统的性能,以下案例中会用到这个包的2个命令mpstat和pidstat。

  • mpstat 是一个常用的多核CPU性能分析工具用来实时查看每个CPU的性能指标,一级所有CPI的平均指标。
# -P ALL 表示监控所有 CPU,后面数字 5 表示间隔 5 秒后输出一组数据
 mpstat -P ALL 5
Linux 4.18.0-147.5.1.el8_1.x86_64 (service) 	2021年06月17日 	_x86_64_	(4 CPU)

11时02分41秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
11时02分46秒  all   53.29    0.00    5.72    0.00    1.22    2.28    0.00    0.00    0.00   37.49
11时02分46秒    0    8.69    0.00   15.56    0.00    0.61    0.20    0.00    0.00    0.00   74.95
11时02分46秒    1   99.40    0.00    0.00    0.00    0.60    0.00    0.00    0.00    0.00    0.00
11时02分46秒    2    2.92    0.00    7.52    0.00    3.34    9.19    0.00    0.00    0.00   77.04
11时02分46秒    3   99.60    0.00    0.00    0.00    0.40    0.00    0.00    0.00    0.00    0.00
参数释义
CPU处理器ID
%usr在internal时间段里,用户态的CPU时间(%),不包含 nice值为负进程 sr/total*100
%nice在internal时间段里,nice值为负进程的CPU时间(%) nice/total*100
%sys在internal时间段里,CPU时间(%) system/total*100
%iowait在internal时间段里,硬盘IO等待(%) iowait/total*100
%irq在internal时间段里,硬中断时间(%) irq/total*100
%soft在internal时间段里,软中断时间(%) softirq/total*100
%steal显示虚拟机管理器在服务另一个虚拟处理器时虚拟CPU处在非自愿等待下花费时间的百分比 steal/total*100
%guest显示运行虚拟处理器时CPU花费时间的百分比 guest/total*100
%gnicegnice/total*100
%idle在internal时间段里,CPU除去等待磁盘IO操作外的因为任何原因而空闲的时间闲置时间(%) idle/total*100
  • pidstat 是一个常用的进程性能分析工具,用来实时查看进程的CPU、内存、I/O以及上下文切换等性能指标。
pidstat -t 5
19时40分33秒   UID       PID   cswch/s nvcswch/s  Command
19时40分38秒     0         9      1.00      0.00  ksoftirqd/0
19时40分38秒     0        10     30.94      0.00  rcu_sched
参数释义
UID用户id
PID进程ID
%usr进程在用户空间占用cpu的百分比
%system进程在内核空间占用cpu的百分比
%guest进程在虚拟机占用cpu的百分比
%wait进程在等待CPU的时间百分比
%CPU进程占用cpu的百分比
CPU处理进程的cpu编号
%Command当前进程对应的命令

uptime

查看平均负载的变化情况:

watch -d uptime

vmstat

vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分 析 CPU 上下文切换和中断的次数。

[root@ ~]# vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0 101120 2083104   1044 692872    0    0     0     0 37327 57872  3  8 89  0  0

需要特别关注的四列内容:

  • cs(context switch)是每秒上下文切换的次数
  • in(interrupt)则是每秒中断的次数
  • r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程 数
  • b(Blocked)则是处于不可中断睡眠状态的进程数
    可以看到,这个例子中的上下文切换次数 cs 是 57872 次,系统中断次数 in 则是 37327 次,而就绪队列长度 r是2此, 不可中断状态进程数 b 是0。

perf

perf 是 Linux 2.6.31 以后内置的性能分析工具。它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题。
在这里插入图片描述

perf top -g
Samples: 785K of event 'cpu-clock:pppH', 4000 Hz, Event count (approx.): 8358801205 lost: 0/0 drop: 0/0
 Overhead     Shared Object                                           Symbol
32.52%         0.04%  imsocket                                [.] imsocketio/events.ListeningClose
22.03%         2.86%  [kernel]                              [k] __softirqentry_text_start

....
   

输出结果中,第一行包含三个数据,分别是采样数(Samples)、事件类型(event)和 事件总数量(Event count)。比如这个例子中,perf 总共采集了 785K CPU 时钟事件,而总事件数则为 8358801205。

另外,采样数需要我们特别注意。如果采样数过少(比如只有十几个),那下面的排序和 百分比就没什么实际参考价值了。
再往下看是一个表格式样的数据,每一行包含四列,分别是:

  1. 第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示
  2. 第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object), 如内核、进程名、动态链接库名、内核模块名等。
  3. 第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
  4. 最后一列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。
    以上面的输出为例,我们可以看到,占用 CPU 时钟最多的是 imsocket不过它 的比例有 32.52%,说明系统 CPU 性能问题并不大,但是这个可以进行优化。 perf top 的使用应该很清楚了吧。

接着再来看第二种常见用法,也就是 perf record 和 perf report。 perf top 虽然实时展 示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后续的分析。 而 perf record 则提供了保存数据的功能,保存后的数据,需要你用 perf report 解析展示。

perf record -g

dstat

dstat 是一个新的性能工具,它吸收了 vmstat、iostat、ifstat 等几种工具的优点, 可以同时观察系统的 CPU、磁盘 I/O、网络以及内存使用情况。

安装

yum install -y dstat

使用说明

安装完后就可以使用了,dstat非常强大,可以实时的监控cpu、磁盘、网络、IO、内存等使用情况。

直接使用dstat,默认使用的是-cdngy参数,分别显示cpu、disk、net、page、system信息,默认是1s显示一条信息。可以在最后指定显示一条信息的时间间隔,如dstat 5是没5s显示一条,dstat 5 10表示没5s显示一条,一共显示10条。

# dstat
----total-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai stl| read  writ| recv  send|  in   out | int   csw 
  0   0  99   0   0|   0     0 |5266B 3868B|   0     0 |1283  2306 
  0   1  99   0   0|   0     0 |4860B 1846B|   0     0 |1384  2488 
  0   0  99   0   0|   0     0 |4798B 4753B|   0     0 |1255  2293 
  0   0  99   0   0|   0    23k|4799B 1754B|   0     0 |1279  2345 
  0   0 100   0   0|   0     0 |4799B 1762B|   0     0 |1189  2174 
  0   0  99   0   0|   0     0 |5075B 2072B|   0     0 |1274  2310 
  3   1  96   0   0|   0     0 |5348B 2294B|   0     0 |1567  2477 
  2   1  97   0   0|   0     0 |5010B 2069B|   0     0 |1510  2424 
  0   0  99   0   0|   0     0 |5075B 1941B|   0     0 |1257  2324 
  0   0  99   0   0|   0     0 |4799B 1754B|   0     0 |1267  2315 
  0   0  99   0   0|   0     0 |4865B 1886B|   0     0 |1260  2274

下面对显示出来的部分信息作一些说明:

  1. cpu:hiq、siq分别为硬中断和软中断次数。
  2. system:int、csw分别为系统的中断次数(interrupt)和上下文切换(context switch)。

语法

dstat [-afv] [options…] [delay [count]]

常用选项

  • -c:显示CPU系统占用,用户占用,空闲,等待,中断,软件中断等信息。
  • -C:当有多个CPU时候,此参数可按需分别显示cpu状态,例:-C 0,1 是显示cpu0和cpu1的信息。
  • -d:显示磁盘读写数据大小。
  • -D hda,total:include hda and total。
  • -n:显示网络状态。
  • -N eth1,total:有多块网卡时,指定要显示的网卡。
  • -l:显示系统负载情况。
  • -m:显示内存使用情况。
  • -g:显示页面使用情况。
  • -p:显示进程状态。
  • -s:显示交换分区使用情况。
  • -S:类似D/N。
  • -r:I/O请求情况。
  • -y:系统状态。
  • –ipc:显示ipc消息队列,信号等信息。
  • –socket:用来显示tcp udp端口状态。
  • -a:此为默认选项,等同于-cdngy。
  • -v:等同于 -pmgdsc -D total。
  • –output 文件:此选项也比较有用,可以把状态信息以csv的格式重定向到指定的文件中,以便日后查看。例:dstat --output /root/dstat.csv & 此时让程序默默的在后台运行并把结果输出到/root/dstat.csv文件中。

实例

如想监控swap,process,sockets,filesystem并显示监控的时间:

dstat -tsp --socket --fs
----system---- ----swap--- ---procs--- --------sockets--------- --filesystem-
     time     | used  free|run blk new|tot  tcp  udp  raw  frg |files  inodes
05-07 16:04:08|  68M 4028M|  0   0    |355   99    4    0    0 | 3616  87574 
05-07 16:04:09|  68M 4028M|0.5   0 1.0|355   99    4    0    0 | 3648  87580 
05-07 16:04:10|  68M 4028M|  0   0 0.5|356  100    4    0    0 | 3680  87586 
05-07 16:04:11|  68M 4028M|  0   0   0|356  100    4    0    0 | 3680  87586 
05-07 16:04:12|  68M 4028M|  0   0   0|356  100    4    0    0 | 3680  87586

sar

sar 是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报 告历史统计数据。

# -n DEV 表示显示网络收发的报告,间隔 1 秒输出一组数据
sar-n DEV 1
Linux 4.18.0-147.5.1.el8_1.x86_64 (service) 	2021年07月02日 	_x86_64_	(2 CPU)

15时09分17秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分18秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分18秒      eth0  15542.00   7773.00    910.68    444.02      0.00      0.00      0.00      0.00

15时09分18秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分19秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分19秒      eth0  15541.00   7771.00    910.61    440.28      0.00      0.00      0.00      0.00

15时09分19秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分20秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分20秒      eth0  15202.00   7602.00    890.75    431.15      0.00      0.00      0.00      0.00

15时09分20秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15时09分21秒        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15时09分21秒      eth0  15565.00   7784.00    912.00    441.44      0.00      0.00      0.00      0.00

对于 sar 的输出界面,我先来简单介绍一下,从左往右依次是:

  • 第一列:表示报告的时间。
  • 第二列:IFACE 表示网卡。
  • 第三、四列:rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数,也就是 PPS。
  • 第五、六列:rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数,也就是 BPS。

sar参数说明

  • -A 汇总所有的报告
  • -a 报告文件读写使用情况
  • -B 报告附加的缓存的使用情况
  • -b 报告缓存的使用情况
  • -c 报告系统调用的使用情况
  • -d 报告磁盘的使用情况
  • -g 报告串口的使用情况
  • -h 报告关于buffer使用的统计数据
  • -m 报告IPC消息队列和信号量的使用情况
  • -n 报告命名cache的使用情况
  • -p 报告调页活动的使用情况
  • -q 报告运行队列和交换队列的平均长度
  • -R 报告进程的活动情况
  • -r 报告没有使用的内存页面和硬盘块
  • -u 报告CPU的利用率
  • -v 报告进程、i节点、文件和锁表状态
  • -w 报告系统交换活动状况
  • -y 报告TTY设备活动状况

hping3

hping3 是一个可以构造 TCP/IP 协议数据包的工具,可以对系统进行安全审计、防火墙 测试等。

# -S 参数表示设置 TCP 协议的 SYN(同步序列号),-p 表示目的端口为 80
# -i u100 表示每隔 100 微秒发送一个网络帧
# 注:如果你在实践过程中现象不明显,可以尝试把 100 调小,比如调成 10 甚至 1 4 
hping3 -S -p 80 -i u100 192.168.0.30

tcpdump

tcpdump 是一个常用的网络抓包工具,常用来分析各种网络问题。

proc 文件系统

proc 文件系统。它是一种内核空间和用户空间进行通信的机制,可以用来查看内核的数据结构,或者用来动态修改内核的配置:

  • /proc/softirqs 提供了软中断的运行情况;
  • /proc/interrupts 提供了硬中断的运行情况。

execsnoop-短时进程追踪工具

在实际工作中,偶尔会遇到系统的CPU使用率和系统平均负载很高,但却找不到高CPU的应用;

产生这个问题的原因:进程有可能在不断的崩溃、重启

通过uptime发现系统负载很高,但是通过top,mpstat,pidstat,perf等工具很难发现是什么进程导致了系统负载和CPU使用率很高;

注:通过上面工具的判断,即不是CPU密集型,也不存在IO等待,也不存在进程、线程争用的情况

execsnoop-专门用于为追踪短时进程(瞬时进程)设计的工具;

它通过 ftrace 实时监控进程的 exec() 行为,并输出短时进程的基本信息,包括进程 PID、父进程 PID、命令行参数以及执行的结果

strace

strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

ldd 查看程序依赖库

来查看程式运行所需的共享库,常用来解决程式因缺少某个库文件而不能运行的一些问题。
查看test程序运行所依赖的库:

ldd test
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00000039a7e00000)
libm.so.6 => /lib64/libm.so.6 (0x0000003996400000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00000039a5600000)
libc.so.6 => /lib64/libc.so.6 (0x0000003995800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003995400000)

pstack 跟踪进程栈

此命令可显示每个进程的栈跟踪。pstack 命令必须由相应进程的属主或 root 运行。可以使用 pstack 来确定进程挂起的位置。此命令允许使用的唯一选项是要检查的进程的 PID。

这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于work状态(如假死状态,好似死循环),使用这个命令就能轻松定位问题所在;可以在一段时间内,多执行几次pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,很可能就是出问题的地方;

[root@webim-service-mq ~]# pstack 23664
Thread 7 (LWP 23832):
#0  runtime.futex () at /usr/local/go/src/runtime/sys_linux_amd64.s:580
#1  0x0000000000432306 in runtime.futexsleep (addr=0xc000261950, val=0, ns=-1) at /usr/local/go/src/runtime/os_linux.go:44
#2  0x000000000040c17f in runtime.notesleep (n=0xc000261950) at /usr/local/go/src/runtime/lock_futex.go:159
#3  0x000000000043b7f9 in runtime.mPark () at /usr/local/go/src/runtime/proc.go:1340
#4  0x000000000043cdf2 in runtime.stopm () at /usr/local/go/src/runtime/proc.go:2257
#5  0x000000000043e32e in runtime.findrunnable (gp=0xc000033000, inheritTime=false) at /usr/local/go/src/runtime/proc.go:2916
#6  0x000000000043f677 in runtime.schedule () at /usr/local/go/src/runtime/proc.go:3125
#7  0x000000000043fbfd in runtime.park_m (gp=0xc000083380) at /usr/local/go/src/runtime/proc.go:3274
#8  0x0000000000469bbb in runtime.mcall () at /usr/local/go/src/runtime/asm_amd64.s:327
#9  0x000000c00020fdc0 in ?? ()
#10 0x0000000000000000 in ?? ()
Thread 6 (LWP 23669):

ipcs

ipcs是Linux下显示进程间通信设施状态的工具。可以显示消息队列、共享内存和信号量的信息。对于程序员非常有用,普通的系统管理员一般用不到此指令。

查看系统使用的IPC资源

查看系统使用的IPC资源

[root@# ~]# ipcs

--------- 消息队列 -----------
键        msqid      拥有者  权限     已用字节数 消息      

------------ 共享内存段 --------------
键        shmid      拥有者  权限     字节     连接数  状态      

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     
0x002fa327 0          root       600        2    

分别查询IPC资源:

# ipcs -m 查看系统使用的IPC共享内存资源
# ipcs -q 查看系统使用的IPC队列资源
# ipcs -s 查看系统使用的IPC信号量资源

free 查询可用内存

free工具用来查看系统可用内存:

[root@webim-service-mq ~]# free
              total        used        free      shared  buff/cache   available
Mem:        3871192     1210960     1027116         508     1633116     2392104
Swap:       4194300       69120     4125180

free的输出一共有2行,第2行为交换区的信息,分别是交换的总量(total),使用量(used)和有多少空闲的交换区(free),这个比较清楚,不说太多。

可以看到,free 输出的是一个表格,其中的数值都默认以字节为单位。表格总共有两行 六列,这两行分别是物理内存 Mem 和交换分区 Swap 的使用情况,而六列中,每列数据 的含义分别为:

  1. 第一列,total 是总内存大小;
  2. 第二列,used 是已使用内存的大小,包含了共享内存;
  3. 第三列,free 是未使用内存的大小;
  4. 第四列,shared 是共享内存的大小;
  5. 第五列,buff/cache 是缓存和缓冲区的大小;
  6. 最后一列,available 是新进程可用内存的大小。

这里尤其注意一下,最后一列的可用内存 available 。available 不仅包含未使用内存,还 包括了可回收的缓存,所以一般会比未使用内存更大。不过,并不是所有缓存都可以回收,因为有些缓存可能正在使用中。

iostat 监视I/O子系统

iostat是I/O statistics(输入/输出统计)的缩写,用来动态监视系统的磁盘操作活动。

命令格式

iostat[参数][时间][次数]

命令功能

通过iostat方便查看CPU、网卡、tty设备、磁盘、CD-ROM 等等设备的活动情况, 负载信息。

命令参数

  1. -C 显示CPU使用情况
  2. -d 显示磁盘使用情况
  3. -k 以 KB 为单位显示
  4. -m 以 M 为单位显示
  5. -N 显示磁盘阵列(LVM) 信息
  6. -n 显示NFS 使用情况
  7. -p[磁盘] 显示磁盘和分区的情况
  8. -t 显示终端和CPU的信息
  9. -x 显示详细信息
  10. -V 显示版本信息

显示所有设备负载情况

iostat 
Linux 4.18.0-147.5.1.el8_1.x86_64 (webim-service-mq) 	2021年07月05日 	_x86_64_	(4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          21.50    0.01   18.61    0.01    0.00   59.88

Device             tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda               0.55         0.25        17.46    2416716  168716452

cpu属性值说明:

  • %user:CPU处在用户模式下的时间百分比。
  • %nice:CPU处在带NICE值的用户模式下的时间百分比。
  • %system:CPU处在系统模式下的时间百分比。
  • %iowait:CPU等待输入输出完成时间的百分比。
  • %steal:管理程序维护另一个虚拟处理器时,虚拟CPU的无意识等待时间百分比。
  • %idle:CPU空闲时间百分比。

注:如果%iowait的值过高,表示硬盘存在I/O瓶颈,%idle值高,表示CPU较空闲,如果%idle值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量。%idle值如果持续低于10,那么系统的CPU处理能力相对较低,表明系统中最需要解决的资源是CPU。

disk属性值说明:

  • rrqm/s:每秒进行 merge 的读操作数目。即 rmerge/s
  • wrqm/s:每秒进行 merge 的写操作数目。即wmerge/s
  • r/s:每秒完成的读 I/O 设备次数。即 rio/s
  • w/s:每秒完成的写 I/O 设备次数。即 wio/s
  • rsec/s:每秒读扇区数。即 rsect/s
  • wsec/s:每秒写扇区数。即 wsect/s
  • rkB/s:每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。
  • wkB/s:每秒写K字节数。是 wsect/s 的一半。
  • avgrq-sz:平均每次设备I/O操作的数据大小 (扇区)。
  • avgqu-sz:平均I/O队列长度。
  • await: 平均每次设备I/O操作的等待时间(毫秒)。
  • svctm:平均每次设备I/O操作的服务时间 (毫秒)。
  • %util:一秒中有百分之多少的时间用于 I/O操作,即被io消耗的cpu百分比

注:如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明I/O 队列太长,io响应太慢,则需要进行必要优化。如果avgqu-sz比较大,也表示有当量io在等待。

cachestat、cachetop 缓存命中情况工具

cachestat:提供了整个操作系统缓存的读写命中情况。
cachetop:提供了每个进程的缓存命中情况。

这两个工具都是 bcc 软件包的一部分,它们基于 Linux 内核的 eBPF(extended Berkeley Packet Filters)机制,来跟踪内核中管理的缓存,并输出缓存的使用和命中情况。

yum install -y bcc-tools
#操作完这些步骤,bcc 提供的所有工具就都安装到 /usr/share/bcc/tools 这个目录中了。不过,bcc 软件包默认不会把这些工具配置到系统的 PATH 路径中,所以得自己手动配置:
# 配置 PATH 路径
export PATH=$PATH:/usr/share/bcc/tools

配置完,就可以运行 cachestat 和 cachetop 命令了。比如,下面就是一个 cachestat 的运行界面,它以 1 秒的时间间隔,输出了 3 组缓存统计数据:

cachestat 1 3
HITS   MISSES  DIRTIES HITRATIO   BUFFERS_MB  CACHED_MB
 0       0        0     0.00%         2        2114
 0       0        0     0.00%         2        2114
5690     0        0   100.00%         2        2114

可以看到,cachestat 的输出其实是一个表格。每行代表一组数据,而每一列代表不同的缓存统计指标。这些指标从左到右依次表示:

我得这个版本没有显示总的io数

  • TOTAL ,表示总的 I/O 次数
  • HITS:表示缓存命中的次数
  • MISSES:表示缓存未命中的次数
  • DIRTIES:表示新增到缓存中的脏页数
  • BUFFERS_MB:表示 Buffers 的大小,以 MB 为单位
  • CACHED_MB:表示 Cache 的大小,以 MB 为单位

接下来再来看一个 cachetop 的运行界面:

cachetop
14:13:41 Buffers MB: 2 / Cached MB: 2129 / Sort: HITS / Order: descending
PID      UID      CMD              HITS     MISSES   DIRTIES  READ_HIT%  WRITE_HIT%
60894    www	  php              5505        0        0     100.0%       0.0%
60934    www	  supervisord      1370        0        0     100.0%       0.0%
60934    www	  php              1111        0        0     100.0%       0.0%

它的输出跟 top 类似,默认按照缓存的命中次数(HITS)排序,展示了每个进程的缓存命 中情况。具体到每一个指标,这里的 HITS、MISSES 和 DIRTIES ,跟 cachestat 里的含义一样,分别代表间隔时间内的缓存命中次数、未命中次数以及新增到缓存中的脏页数。

而 READ_HIT 和 WRITE_HIT ,分别表示读和写的缓存命中率。

pcstat 查看文件在内存中的缓存大小以及缓存比例

pcstat 是一个基于 Go 语言开发的工具,所以安装它之前,首先应该安装 Go 语言

 go get github.com/tobert/pcstat/pcstat

全部安装完成后,你就可以运行 pcstat 来查看文件的缓存情况了。比如,下面就是一个 pcstat 运行的示例,它展示了 /bin/ls 这个文件的缓存情况:

pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name    | Size (bytes)   | Pages      | Cached    | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 157376         | 39         | 0       | 000.000 |
+---------+----------------+------------+-----------+---------+

这个输出中,Cached 就是 /bin/ls 在缓存中的大小,而 Percent 则是缓存的百分比。你看到它们都是 ,这说明 /bin/ls 并不在缓存中。

接着,如果你执行一下 ls 命令,再运行相同的命令来查看的话,就会发现 /bin/ls 都在缓存中了:

ls
pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name    | Size (bytes)   | Pages      | Cached    | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 157376         | 39         | 13        | 033.333 |
+---------+----------------+------------+-----------+---------+

memleak 检测内存泄漏的工具

memleak 可以跟踪系统或 指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况 (默认 5 秒)。

当然,memleak 是 bcc 软件包中的一个工具,我们一开始就装好了,执行/usr/share/bcc/tools/memleak 就可以运行它。

# -a 表示显示每个内存分配请求的大小以及地址
# -p 指定案例应用的 PID 号
/usr/share/bcc/tools/memleak -p 23664 -a

iostat 磁盘 I/O 观测

iostat 是最常用的磁盘 I/O 性能观测工具,它提供了每个磁盘的使用率、IOPS、吞吐量等 各种常见的性能指标,当然,这些指标实际上来自 /proc/diskstats。

iostat 的输出界面如下

# -d -x 表示显示所有磁盘 I/O 的指标
iostat -d -x 1
Linux 4.18.0-147.5.1.el8_1.x86_64 (webim-service-mq) 	2021年07月29日 	_x86_64_	(4 CPU)

Device            r/s     w/s     rkB/s     wkB/s   rrqm/s   wrqm/s  %rrqm  %wrqm r_await w_await aqu-sz rareq-sz wareq-sz  svctm  %util
vda              0.01    0.56      0.47     23.48     0.00     0.07   3.77  11.71   14.87   37.98   0.02    38.50    42.24   0.37   0.02

Device            r/s     w/s     rkB/s     wkB/s   rrqm/s   wrqm/s  %rrqm  %wrqm r_await w_await aqu-sz rareq-sz wareq-sz  svctm  %util
vda              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   0.00   0.00

从这里可以看到,iostat 提供了非常丰富的性能指标。第一列的 Device 表示磁盘设备的名字,其他各列指标,虽然数量较多,但是每个指标的含义都很重要。为了方便你理 解,我把它们总结成了一个表格。
在这里插入图片描述
这些指标中,要注意:

  • %util ,就是我们前面提到的磁盘 I/O 使用率;
  • r/s+ w/s ,就是 IOPS;
  • rkB/s+wkB/s ,就是吞吐量;
  • r_await+w_await ,就是响应时间

在观测指标时,也别忘了结合请求的大小( rareq-sz 和 wareq-sz)一起分析。

进程 I/O 观测

除了每块磁盘的 I/O 情况,每个进程的 I/O 情况也是我们需要关注的重点。

上面提到的 iostat 只提供磁盘整体的 I/O 性能数据,缺点在于,并不能知道具体是哪些进程在进行磁盘读写。要观察进程的 I/O 情况,还可以使用 pidstat 和 iotop 这两个工具。

pidstat 是我们的老朋友了,这里我就不再啰嗦它的功能了。给它加上 -d 参数,你就可以 看到进程的 I/O 情况,如下所示:

pidstat -d 1
17时24分39秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
17时24分44秒     0       266      0.00      0.80      0.00  jbd2/vda1-8
17时24分44秒     0       504      0.00     12.80      0.00  jbd2/vdb-8
17时24分44秒    27      1387      0.00      0.80      0.00  mysqld
17时24分44秒   997      8908      0.00      1.60      0.00  nginx
17时24分44秒  1000     25621      0.00     14.40      0.00  php-fpm
17时24分44秒  1000     26288      0.00     17.60      0.00  php-fpm

从 pidstat 的输出你能看到,它可以实时查看每个进程的 I/O 情况,包括下面这些内容。

  • 用户 ID(UID)和进程 ID(PID) 。
  • 每秒读取的数据大小(kB_rd/s) ,单位是 KB。
  • 每秒发出的写请求数据大小(kB_wr/s) ,单位是 KB。
  • 每秒取消的写请求数据大小(kB_ccwr/s) ,单位是 KB。
  • 块 I/O 延迟(iodelay),包括等待同步块 I/O 和换入块 I/O 结束的时间,单位是时钟周期。

iotop 按照 I/O 大小对进程排序

iotop。它是一个类似于 top 的工具,你可以按照 I/O 大小对进程排序,然后找到 I/O 较大的那些进程。

iotop
Total DISK READ :	0.00 B/s | Total DISK WRITE :      35.27 K/s
Actual DISK READ:	0.00 B/s | Actual DISK WRITE:     368.40 K/s
TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                                                                                                       
16811 be/2 root        0.00 B/s    3.92 K/s  0.00 %  0.00 % AliYunDun

从这个输出,可以看到,前两行分别表示,进程的磁盘读写大小总数和磁盘真实的读写 大小总数。因为缓存、缓冲区、I/O 合并等因素的影响,它们可能并不相等。

剩下的部分,则是从各个角度来分别表示进程的 I/O 情况,包括线程 ID、I/O 优先级、每 秒读磁盘的大小、每秒写磁盘的大小、换入和等待 I/O 的时钟百分比等。

lsof 查看进程打开文件列表

lsof -p 23664
COMMAND    PID USER   FD      TYPE   DEVICE SIZE/OFF      NODE NAME
imsocket 23664 root  cwd       DIR    253,1       56 302019283 /data/imsocket
imsocket 23664 root  rtd       DIR    253,1      272       128 /
imsocket 23664 root  txt       REG    253,1 13773370 302024957 /data/imsocket/imsocket
imsocket 23664 root    0r     FIFO     0,13      0t0  61209341 pipe
imsocket 23664 root    1w     FIFO     0,13      0t0  61209342 pipe
imsocket 23664 root    2w     FIFO     0,13      0t0  61209343 pipe
imsocket 23664 root    4u  a_inode     0,14        0     11876 [eventpoll]
imsocket 23664 root    5r     FIFO     0,13      0t0  61210406 pipe
imsocket 23664 root    6w     FIFO     0,13      0t0  61210406 pipe
imsocket 23664 root    7u     sock      0,9      0t0  61210408 protocol: TCP
imsocket 23664 root    9u     IPv4 61211103      0t0       TCP nsqHost:43566->nsqHost:PowerAlert-nsa (ESTABLISHED)
imsocket 23664 root   10u     IPv6 61212017      0t0       TCP *:9501 (LISTEN)
imsocket 23664 root   11u     IPv4 61209344      0t0       TCP nsqHost:43568->nsqHost:PowerAlert-nsa (ESTABLISHED)
imsocket 23664 root   12u     IPv4 61212019      0t0       TCP nsqHost:43570->nsqHost:PowerAlert-nsa (ESTABLISHED)
imsocket 23664 root   13u     IPv4 61212020      0t0       TCP nsqHost:43572->nsqHost:PowerAlert-nsa (ESTABLISHED)
imsocket 23664 root   14u     IPv4 61209347      0t0       TCP nsqHost:43574->nsqHost:PowerAlert-nsa (ESTABLISHED)

COMMAND:进程的名称!

  • PID: 进程标识符!
  • USER: 进程所有者!
  • FD: 文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等!
  • TYPE: 文件类型,如DIR、REG,MEM等!
  • DEVICE: 指定磁盘的名称!
  • SIZE: 文件的大小
  • NODE: 索引节点(文件在磁盘上的标识)
  • NAME: 打开的文件名称

FD 列中的文件描述符意义:

  • cwd 表示应用程序的当前工作目录,也是该应用程序启动的目录,除非它本身对这个目录进行更改
  • txt 表示该类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的/sbin/init程序
  • 数值 表示应用程序的文件描述符,打开该文件时返回的整数。如上的最后一行文件/dev/initctl,其文件描述符为 10;dev/null的描述符为2!
  • u 表示该文件被打开并处于读取/写入模式,而不是只读®或只写(w)模式。大写的W表示该应用程序具有对整个文件的写锁。该文件描述符用于确保每次只能打开一个应用程序实例!
  • 初始打开每个应用程序时,都具有三个文件描述符,从0到2,分别表示标准输入、输出和错误流。所以大多数应用程序所打开的文件的FD都是从3开始。

Type 列中的文件描述符意义:

  • REG 表示文件
  • DIR 表示目录
  • CHR 表示字符设备
  • BLK 表示和块设备
  • UNIX 表示UNIX 域套接字
  • FIFO 表示先进先出(FIFO)队列
  • IPv4 表示网际协议(IP)套接字

filetop 跟踪内核中文件的读写情况

它是 bcc 软件包的一部分,基于 Linux 内核的 eBPF(extended Berkeley Packet Filters)机制,主要跟踪内核中文件的读写情况,并 输出线程 ID(TID)、读写大小、读写类型以及文件名称。

# -C 选项表示输出新内容时不清空屏幕
filetop -C
TID    COMM             READS  WRITES R_Kb    W_Kb    T FILE
27168  supervisord       0      1      0       0      R supervisord.log-20210728
156999 php               8      0      32      0      R openssl.cnf
156999 php               4      0      32      0      R SymfonyStyle.php
31177  AliYunDun         4      0      31      0      R stat
156999 php               3      0      24      0      R .env
156999 php               4      0      16      0      R hosts
156999 php               4      0      16      0      R opensslcnf.txt

我们会看到,filetop 输出了 8 列内容,分别是线程 ID、线程命令行、读写次数、读写的大 小(单位 KB)、文件类型以及读写的文件名称

多观察一会儿,就会发现,每隔一段时间,线程号为 156999 的 php 应用就会先写入的 openssl.cnf 文件,再大量地读。

运行下面的ps命令查看一下:

ps -efT |grep 156999
www       156999  156999   27168  0 17:37 ?        00:00:00 /usr/bin/php /data/api/artisan user-cache

我们看到,这个线程正是案例应用 156999 的线程。终于可以先松一口气,不过还没完, filetop 只给出了文件名称,却没有文件路径,还得继续找啊。

在使用opensnoop工具 。它同属于 bcc 软件包,可以动态跟踪内核中的 open 系统调用。这样,我们就可以找出这些文件的路径。

opensnoop

fio 文件系统和磁盘 I/O 性能基准测试工具

fio(Flexible I/O Tester)正是最常用的文件系统和磁盘 I/O 性能基准测试工具。它提供了大量的可定制化选项,可以用来测试,裸盘或者文件系统在各种场景下的 I/O 性能,包 括了不同块大小、不同 I/O 引擎以及是否使用缓存等场景。
安装

yum install -y fio

安装完成后,就可以执行 man fio 查询它的使用方法。

fio 的选项非常多, 我们通过几个常见场景的测试方法,介绍一些最常用的选项。这些常 见场景包括随机读、随机写、顺序读以及顺序写等,你可以执行下面这些命令来测试:

# 随机读
fio -name=randread -direct=1 -iodepth=64 -rw=randread -ioengine=libaio -bs=4k -size=1G -

# 随机写
fio -name=randwrite -direct=1 -iodepth=64 -rw=randwrite -ioengine=libaio -bs=4k -size=1G

# 顺序读
fio -name=read -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=4k -size=1G -numjobs=10

# 顺序写
fio -name=write -direct=1 -iodepth=64 -rw=write -ioengine=libaio -bs=4k -size=1G -numjob

在这其中,有几个参数需要我们重点关注一下。

  • direct,表示是否跳过系统缓存。上面示例中,我设置的 1 ,就表示跳过系统缓存。
  • iodepth,表示使用异步 I/O(asynchronous I/O,简称 AIO)时,同时发出的 I/O 请 求上限。在上面的示例中,我设置的是 64。
  • rw,表示 I/O 模式。上面的示例中, read/write 分别表示顺序读 / 写,而 randread/randwrite 则分别表示随机读 / 写。
  • ioengine,表示 I/O 引擎,它支持同步(sync)、异步(libaio)、内存映射 (mmap)、网络(net)等各种 I/O 引擎。上面示例中,设置的 libaio 表示使用异 步 I/O。
  • bs,表示 I/O 的大小。示例中,我设置成了 4K(这也是默认值)。
  • filename,表示文件路径,当然,它可以是磁盘路径(测试磁盘性能),也可以是文件 路径(测试文件系统性能)。示例中,我把它设置成了磁盘 /dev/sdb。不过注意,用磁盘路径测试写,会破坏这个磁盘中的文件系统,所以在使用前,一定要事先做好数据备份。

pktgen Linux网络测试工具

Linux 内核自带的高性能网络测试工具 pktgen。 pktgen 支持丰富的自定义选项,方便你根据实际需要构造所需网络包,从而更准确地测 试出目标服务器的性能。

不过,在 Linux 系统中,并不能直接找到 pktgen 命令。因为 pktgen 作为一个内核线程来运行,需要加载 pktgen 内核模块后,再通过 /proc 文件系统来交互。下面就是 pktgen 启动的两个内核线程和 /proc 文件系统的交互文件:

modprobe pktgen
ps -ef | grep pktgen| g rep-v grep 3 
root 26384 2 0 06:17 ?    00:00:00 [kpktgend_0]
root 26385 2 0 06:17 ?    00:00:00 [kpktgend_1]
ls /proc/net/pktgen/
kpktgend_0 kpktgend_1 pgctrl

pktgen 在每个 CPU 上启动一个内核线程,并可以通过 /proc/net/pktgen 下面的同名文件,跟这些线程交互;而 pgctrl 则主要用来控制这次测试的开启和停止。

如果 modprobe 命令执行失败,说明你的内核没有配置
CONFIG_NET_PKTGEN 选项。这就需要你配置 pktgen 内核模块(即
CONFIG_NET_PKTGEN=m)后,重新编译内核,才可以使用。

在使用 pktgen 测试网络性能时,需要先给每个内核线程 kpktgend_X 以及测试网卡,配 置 pktgen 选项,然后再通过 pgctrl 启动测试。

TCP/UDP 性能压测

说到 TCP 和 UDP 的测试,已经很熟悉了,甚至可能一下子就能想到相应的测试工具,比如 iperf 或者 netperf。

iperf 和 netperf 都是最常用的网络性能测试工具,测试 TCP 和 UDP 的吞吐量。它们都以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。

接下来,我们就以 iperf 为例,看一下 TCP 性能的测试方法。目前,iperf 的最新版本为 iperf3,你可以运行下面的命令来安装:

yum install iperf3

然后,在目标机器上启动 iperf 服务端:

# -s 表示启动服务端,-i 表示汇报间隔,-p 表示监听端口
iperf3 -s -i 1 -p 10000

接着,在另一台机器上运行 iperf 客户端,运行测试:

# -c 表示启动客户端,192.168.0.30 为目标服务器的 IP 2 # -b 表示目标带宽 (单位是 bits/s)
# -t 表示测试时间
# -P 表示并发数,-p 表示目标服务器监听端口
iperf3 -c 172.31.36.80 -b 10G -t 15 -P 2 -p 10000

稍等一会儿(15 秒)测试结束后,回到目标服务器,查看 iperf 的报告:

[ ID] Interval           Transfer     Bitrate
[  5]   0.00-15.04  sec  1.51 GBytes   860 Mbits/sec                  receiver
[  8]   0.00-15.04  sec  1.24 GBytes   709 Mbits/sec                  receiver
[SUM]   0.00-15.04  sec  2.75 GBytes  1.57 Gbits/sec                  receiver

最后的 SUM 行就是测试的汇总结果,包括测试时间、数据传输量以及带宽等。按照发送和接收,这一部分又分为了 sender 和 receiver 两行。

从测试结果你可以看到,这台机器 TCP 接收的带宽(吞吐量)为 1.57 Gb/s, 跟目标的 10Gb/s 相比,还是有些差距的。

HTTP 性能压测

从传输层再往上,到了应用层。有的应用程序,会直接基于 TCP 或 UDP 构建服务。当 然,也有大量的应用,基于应用层的协议来构建服务,HTTP 就是最常用的一个应用层协 议。比如,常用的 Apache、Nginx 等各种 Web 服务,都是基于 HTTP。

要测试 HTTP 的性能,也有大量的工具可以使用,比如 ab、webbench 等,都是常用的 HTTP 压力测试工具。其中,ab 是 Apache 自带的 HTTP 压测工具,主要测试 HTTP 服 务的每秒请求数、请求延迟、吞吐量以及请求延迟的分布情况等。

运行下面的命令,你就可以安装 ab 工具:

yum install -y httpd-tools

运行 ab 命令,测试 Nginx 的性能:

# -c 表示并发请求数为 1000,-n 表示总的请求数为 10000
ab -c 1000 -n 10000 http://172.31.36.80/
....
Server Software:        nginx
Server Hostname:        172.31.36.80
Server Port:            80

Document Path:          /
Document Length:        3196 bytes

Concurrency Level:      1000
Time taken for tests:   0.462 seconds
Complete requests:      10000
Failed requests:        4
   (Connect: 0, Receive: 0, Length: 0, Exceptions: 4)
Total transferred:      34460000 bytes
HTML transferred:       31960000 bytes
Requests per second:    21634.86 [#/sec] (mean)
Time per request:       46.222 [ms] (mean)
Time per request:       0.046 [ms] (mean, across all concurrent requests)
Transfer rate:          72806.37 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   12   1.7     12      18
Processing:     5   16   8.5     15     233
Waiting:        0   13   8.4     11     230
Total:         14   28   8.6     27     247

Percentage of the requests served within a certain time (ms)
  50%     27
  66%     29
  75%     31
  80%     31
  90%     34
  95%     36
  98%     40
  99%     41
 100%    247 (longest request)
 

可以看到,ab 的测试结果分为三个部分,分别是请求汇总、连接时间汇总还有请求延迟汇总。以上面的结果为例,我们具体来看。

在请求汇总部分,可以看到:

  • Requests per second: 21634.86
  • 每个请求的延迟(Time per request)分为两行,第一行的 46.222 ms 表示平均延迟,包括了线程运行的调度时间和网络请求响应时间,而下一行的 0.046 ms ,则表示实际请求 的响应时间;
  • Transfer rate 表示吞吐量(BPS)为 72806.37 KB/s。

连接时间汇总部分,则是分别展示了建立连接、请求、等待以及汇总等的各类时间,包括最小、最大、平均以及中值处理时间。

最后的请求延迟汇总部分,则给出了不同时间段内处理请求的百分比,比如, 90% 的请 求,都可以在 34ms 内完成。

应用负载性能

当使用 iperf 或者 ab 等测试工具,得到 TCP、HTTP 等的性能数据后,这些数据是否就能表示应用程序的实际性能呢?我想,那肯定不是的。

比如,应用程序基于 HTTP 协议,为最终用户提供一个 Web 服务。这时,使用 ab 工具,可以得到某个页面的访问性能,但这个结果跟用户的实际请求,很可能不一致。因 为用户请求往往会附带着各种各种的负载(payload),而这些负载会影响 Web 应用程序内部的处理逻辑,从而影响最终性能。

那么,为了得到应用程序的实际性能,就要求性能工具本身可以模拟用户的请求负载,而 iperf、ab 这类工具就无能为力了。但是,我们还可以用 wrk、TCPCopy、Jmeter 或者 LoadRunner 等实现这个目标。

以 wrk 为例,它是一个 HTTP 性能测试工具,内置了 LuaJIT,方便你根据实际需求,生成所需的请求负载,或者自定义响应的处理方法。

wrk 工具本身不提供 yum 或 apt 的安装方法,需要通过源码编译来安装。

git clone https://github.com/wg/wrk.git
cd wrk
make
cp wrk /usr/local/bin/

wrk 的命令行参数比较简单。比如,我们可以用 wrk ,来重新测一下前面已经启动的 Nginx 的性能。

# -c 表示并发连接数 1000,-t 表示线程数为 2
wrk -c 1000 -t 2 http://api.tickeup.com/oss/getstsinfo/
Running 10s test @ http://api.tickeup.com/oss/getstsinfo/
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   286.14ms  207.38ms   1.81s    65.46%
    Req/Sec     1.49k     1.16k    6.24k    77.60%
  25253 requests in 10.03s, 7.60MB read
  Socket errors: connect 0, read 0, write 0, timeout 315
  Non-2xx or 3xx responses: 24950
Requests/sec:   2517.19
Transfer/sec:    775.54KB

这里使用 2 个线程、并发 1000 连接,测试了应用程序的性能。你可以看到,每秒请求数为 2517.19,吞吐量为 775.54KB,平均延迟为 286.14ms。

time

time 命令可以用来运行命令并报告CPU用量。它可能在操作系统的/usr/bin目录下,或者在shell里内建。

[root@node]# time
real	0m0.000s
user	0m0.000s
sys	0m0.000s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值