性能诊断
在做性能诊断时,一般从两个方面入手,一个是观察机器的运行状态,看看是否有什么瓶颈导致性能不佳。另一种是通过程序细节,看看具体哪些函数或者变量导致机器出现了瓶颈。本文主要介绍前面的方式,从CPU,内存,I/O,网络入手,用基本命令分析系统的瓶颈。
top命令分析
top实时显示系统各个进程的资源占用情况。可以通过top命令来大致判断可能的性能瓶颈出现在哪里,然后通过相关工具做进一步分析。
第一行重点关注 load average: 0.09, 0.07, 0.05: 三个数字分别表示1分钟,5分钟,15分钟的系统负载情况。数据是每隔5秒检查一次活跃的进程数,然后按特定的算法计算出的数值。如果这个数除以逻辑cpu的数量,结果高于5的时候表明系统在超负荷运转
第三行显示了cpu的状态信息 Cpu(s): 1.4%us, 1.5%sy, 0.0%ni, 97.0%id, 0.2%wa, 0.0%hi, 0.0%si, 0.0%st
us — 用户空间占用CPU的百分比。
sy — 内核空间占用CPU的百分比。
ni — 改变过优先级的进程占用CPU的百分比
id — 空闲CPU百分比
wa — IO等待占用CPU的百分比
hi — 硬中断(Hardware IRQ)占用CPU的百分比
si — 软中断(Software Interrupts)占用CPU的百分比
st — (Steal time)。虚拟 CPU 等待实际 CPU 的时间的百分比。如果你的服务是运行在主机上的虚拟机中,需要关注此值。过高的此值,说明主机上运行的虚拟机过多,引起了cpu时间竞争。
上面的统计是针对所有cpu的平均值,如果要查看具体的cpu值,可以按 1。如果cpu用量分配不均匀,我们要找出引起此现象的进程来,尝试通过绑定cpu的方式来解决。
1 2 3 4 5 |
$ps -eo pid,cmd,args,psr | grep nginx 4151 grep nginx grep nginx 1 4440 nginx: master process /opt/ nginx: master process /opt/ 0 4445 nginx: worker process nginx: worker process 1 4446 nginx: worker process nginx: worker process 0 |
我们可以看到nginx有两个worker进程,一个分配到了cpu0上,一个分配到了cpu1上。如果cpu分配不均匀,我们可以通过 taskset命令把进程分配到指定的cpu上。
第四行显示了内存信息 Mem: 4057324k total, 3882404k used, 174920k free, 320412k buffers
total — 物理内存总量(4G)
used — 使用中的内存总量(3.8G)
free — 空闲内存总量(174M)
buffers — 缓存的内存总量(320M)
第五行swap分区信息 Swap: 0k total, 0k used, 0k free, 2670272k cached
total — 交换区总量(0K)
used — 使用的交换区总量(0K)
free — 空闲交换区总量(0K)
cached — 缓冲的交换区总量(2.6GB)
在linux系统中,free数量是一直减少的,但是并不是系统出了问题。内核使用内存后,会缓存之前的数据,并不释放。可以通过公式计算大体的内存容量。第四行free + 第四行buffers+第五行cached 就是可用的内存总量。
从第七行开始就列出了活跃的进程列表。能从这里直观的看到cpu及内存占用量。通过 SHIFT + P可以对CPU用量排序, SHIFT + M可以对内存用量排序。
PR — 进程优先级
NI — nice值。负值表示高优先级,正值表示低优先级
VIRT — 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
RES — 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
SHR — 共享内存大小,单位kb
S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
%CPU — 上次更新到现在的CPU时间占用百分比
%MEM — 进程使用的物理内存百分比
进程使用的内存用量可以通过 RES – SHR 简单的估算出来。 也可以通过ps命令监测进程。
CPU性能分析
mpstat
多处理器统计信息工具mpstat,能够报告每个CPU的统计信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$mpstat -P ALL 1 Linux 2.6.32-220.23.2.ali878.el6.x86_64 (e011239171082.et15sqa) 04/05/2017 _x86_64_ (2 CPU) 02:28:45 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 02:28:46 PM all 0.51 0.00 0.51 0.00 0.00 0.00 0.00 0.00 98.98 02:28:46 PM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 02:28:46 PM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 02:28:46 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 02:28:47 PM all 1.03 0.00 1.03 0.00 0.00 0.00 0.00 0.00 97.95 02:28:47 PM 0 1.02 0.00 2.04 0.00 0.00 0.00 0.00 0.00 96.94 02:28:47 PM 1 1.02 0.00 1.02 0.00 0.00 0.00 0.00 0.00 97.96 02:28:47 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 02:28:48 PM all 0.51 0.00 0.51 0.00 0.00 0.00 0.00 0.00 98.98 02:28:48 PM 0 1.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.99 02:28:48 PM 1 1.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.99 02:28:48 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 02:28:49 PM all 0.51 0.00 0.51 0.00 0.00 0.00 0.00 0.00 98.98 02:28:49 PM 0 1.01 0.00 1.01 0.00 0.00 0.00 0.00 0.00 97.98 02:28:49 PM 1 0.00 0.00 1.01 0.00 0.00 0.00 0.00 0.00 98.99 |
上面显示了一共有两个CPU用量。具体值与top显示的第三行数据含义是一样的。
如果%sys数值过高,说明应该程序在大量的调用内核方法,利用strace命令进一步确定是哪个内核函数引起的。
strace
strace是一个系统调用接口的调试器。`strace -T -p 可以查看pid进程的系统调用情况。-T显示了系统调用时间。
下面是对进程1009的系统调用统计。
1 2 3 4 5 6 7 8 9 10 |
$sudo strace -cp 1009 Process 1009 attached - interrupt to quit ^CProcess 1009 detached % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 67.61 0.002000 43 46 nanosleep 27.72 0.000820 17 47 recvfrom 4.67 0.000138 3 46 sendto ------ ----------- ----------- --------- --------- ---------------- 100.00 0.002958 139 total |
如果想查看具体的调用方法,可以使用 -e参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$sudo strace -e recvfrom -T -p 1009 Process 1009 attached - interrupt to quit recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 recvfrom(20, "\1\0\1\0\0\0\5\0<\0H\0\316", 131072, 0, NULL, NULL) = 13 |
pidstat
pidstat工具按进程或线程打印CPU用量,包括用户态和系统态时间的分解。默认情况下,仅循环输出活动进程的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
pidstat 2 Linux 2.6.32-220.23.2.ali878.el6.x86_64 (e011239171082.et15sqa) 04/06/2017 _x86_64_ (2 CPU) 09:23:46 AM PID %usr %system %guest %CPU CPU Command 09:23:48 AM 2470 0.50 0.50 0.00 1.00 1 alisentry_cli 09:23:48 AM 4724 0.00 0.50 0.00 0.50 1 staragent-core 09:23:48 AM 25041 0.00 0.50 0.00 0.50 1 logagent 09:23:48 AM 29936 0.00 0.50 0.00 0.50 0 pidstat 09:23:48 AM PID %usr %system %guest %CPU CPU Command 09:23:50 AM 695 0.50 0.00 0.00 0.50 1 alisentry_watch 09:23:50 AM 2470 0.50 0.50 0.00 1.00 1 alisentry_cli 09:23:50 AM 4724 0.50 0.50 0.00 1.00 1 staragent-core 09:23:50 AM 4725 1.00 1.00 0.00 2.00 1 staragent-ppf 09:23:50 AM 29936 0.50 0.50 0.00 1.00 0 pidstat |
内存性能分析
vmstat
vmstat是虚拟内存统计信息命令。它提供包括当前内存和换页在内的系统内存健康程度总览。
1 2 3 4 5 6 7 8 |
$vmstat 1 -Sm procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 91 325 2586 0 0 0 11 1 0 1 1 97 0 0 0 0 0 91 325 2586 0 0 0 188 2814 4778 5 4 91 0 0 0 0 0 91 325 2586 0 0 0 172 2673 4773 2 2 95 1 0 0 0 0 91 325 2586 0 0 0 0 2446 4651 1 1 99 0 0 1 0 0 91 325 2586 0 0 0 0 2373 4679 1 1 99 0 0 |
vmstat默认单位为KB。大内存系统的话,数据列会不对齐而影响阅读。可以用-S选项修改输出单位为MB。
- r,可运行队列的线程数,这些线程都是可运行状态,只不过 CPU 暂时不可用,每个可运行队列不应该超过3个线程(每处理器),比如:双处理器系统的可运行队列里不应该超过6个线程;
-
b,被 blocked 的进程数,正在等待 IO 请求;
-
swpd,已使用的 SWAP 空间大小;
-
free,可用的物理内存大小;
- buff,物理内存用来缓存读写操作的 buffer 大小;
- cache,物理内存用来缓存进程地址空间的 cache 大小;
- si,数据从 SWAP 读取到 RAM(swap in)的大小;
- so,数据从 RAM 写到 SWAP(swap out)的大小;
- bi,磁盘块从文件系统或 SWAP 读取到 RAM(blocks in)的大小,block 为单位;
- bo,磁盘块从 RAM 写到文件系统或 SWAP(blocks out)的大小,block 为单位;
- in,被处理过的中断数
- cs,系统上正在做上下文切换的数目
I/O性能分析
iostat
iostat汇总了单个磁盘的统计信息,统计信息来源由内核维护,工具开销几乎可以忽略不计。
1 2 3 4 5 6 7 8 |
$iostat -k Linux 2.6.32-220.23.2.ali878.el6.x86_64 (e011239171082.et15sqa) 04/16/2017 _x86_64_ (2 CPU) avg-cpu: %user %nice %system %iowait %steal %idle 1.14 0.00 1.44 0.21 0.00 97.21 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn vda 2.68 0.07 23.24 1463537 475937652 |
- tps:每秒事务数(IOPS)
- kBread/s、kBwrtn/s:每秒读取KB数和每秒写入KB数
- kBread、kBwrtn:总共读取和写入的KB数
1 2 3 4 5 6 7 8 9 10 |
$iostat -xkdz 1 Linux 2.6.32-220.23.2.ali878.el6.x86_64 (e011239171082.et15sqa) 04/16/2017 _x86_64_ (2 CPU) Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util vda 0.00 3.12 0.00 2.68 0.07 23.24 17.39 0.05 18.28 2.20 0.59 Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util vda |
- rrqm/s:每秒合并放入驱动请求队列的读请求数
- wrqm/s:每秒合并放入驱动请求队列的写请求数
- r/s:每秒发给磁盘设备的读请求数
- w/s:每秒发给磁盘设备的写请求数
- rkB/s:每秒从磁盘设备读取的KB数
- wkB/s:每秒向磁盘设备写入的KB数
- argrq-sz:平均请求大小,单位为扇区(512B)
- qvgqu-sz:在驱动请求队列和在设置中活跃的平均请求数
- await:平均I/O响应时间,包括在驱动请求队列里等待和设置的I/O响应时间(ms)
- svctm:(推断)磁盘设备的I/O平均响应时间(ms)
- %util:设备忙处理I/O请求的百分比(使用率)
IO分为顺序IO和随机IO。监测前我们需要清楚系统偏向哪种IO。比如mysql应用更偏向于顺序IO,顺序请求大量数据。web服务应用更多是随机IO。但这也不是绝对的。比如大量的单行查询,可能会造成mysql表现为随机IO。
顺序IO更重视每次IO的吞吐能力(KB per IO)。用每秒读写 IO 字节数除以每秒读写 IOPS 数,rkB/s 除以 r/s,wkB/s 除以 w/s来评估。
随机IO依赖于磁盘的每秒能 IO 的次数,随机 IO 每秒同时会有更多的请求数产生,所以磁盘的每秒能 IO 多少次是关键。比如说SSD每次IO的执行时间短,IOPS就会比较大,在随机应用里面,SSD比普通硬盘性能要好。
网络性能分析
tcpdump
tcpdump是一个网络包分析工具,可以把网络中的包保存起来,供上层工具分析(比如wireshark,tcptrace)。功能十分强大,支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。可以使用tcpdump跟踪网络请求,学习网络协议等。
在docker开发时,访问数据库非常慢。我们实地抓包分析下。 tcpdump port 3306 -n -w 0416.pcap,对端口号进行过滤,只抓数据库访问的包,然后保存到文件0416.pcap。
我们用tcptrace进行简单分析。后面的输出进行了省略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
tcptrace -lr ../0416.pcap 1 arg remaining, starting with '../0416.pcap' Ostermann's tcptrace -- version 6.6.7 -- Thu Nov 4, 2004 23 packets seen, 23 TCP packets traced elapsed wallclock time: 0:00:00.002718, 8462 pkts/sec analyzed trace file elapsed time: 0:00:00.347191 TCP connection info: 1 TCP connection traced: TCP connection 1: host a: bogon:52480 host b: 11.238.163.17:3306 complete conn: yes first packet: Sun Apr 16 18:03:02.963317 2017 last packet: Sun Apr 16 18:03:03.310508 2017 elapsed time: 0:00:00.347191 total packets: 23 filename: ../0416.pcap ...... RTT samples: 6 RTT samples: 7 RTT min: 0.2 ms RTT min: 0.0 ms RTT max: 41.1 ms RTT max: 48.8 ms RTT avg: 7.2 ms RTT avg: 7.2 ms RTT stdev: 16.6 ms RTT stdev: 18.4 ms RTT from 3WHS: 41.1 ms RTT from 3WHS: 0.1 ms ...... |
从上图看到,我们只抓了一个TCP请求周期。elapsed time 关注下这个时间,从第一个包到最后一个包的截止时间,用了347毫秒。再来看下具体的RTT,可以看到一个包来回用了40多毫秒。详细的内容解读,通过 tcptrace -houtput来说明。
用tcpdump抓包后,通过wireshark用图形化的方式进行分析
系统概况
sar 工具相当于系统的活动监视器。它的特点是可以连续对系统取样,获得大量的取样数据;取样数据和分析的结果都可以存入文件,所需的负载很小。sar 会记录系统历史的状态。sar 选项较多,取重要的几个选项来说明。
- -P ALL :每个CPU利用率
- -u:CPU利用率
- -q:CPU运行队列长度
- -r:内存利用率
- -S:交换区利用率
- -d:磁盘统计信息
- -n DEV:网络接口统计信息
- -B 换页信息统计
更多的统计分析可以查看man手册。