10行命令60秒快速定位性能瓶颈

帅昕xindoo 2020-02-05

linux java 性能优化 性能 CPU 磁盘

今天为大家翻译一篇来自Netflix技术博客的Linux Performance Analysis in 60,000 Milliseconds,作者是著名linux内核工程师&性能优化专家Brendan D. Gregg和Netflix性能团队。这篇文章会教你怎么用10个常用的linux工具在60秒内完成对性能问题的初步诊断。

当你登录到linux服务器处理性能问题的时候,最开始的一分钟你会做些啥?
Netflix有大量的EC2云服务主机,也有很多检测和排查性能问题的工具。比如像云监控工具Atlas和实例分析工具Vector。这些工具帮我们解决了大部分性能问题,但有时候我们仍需要登录到服务器上运行一些标准的Linux性能排查工具。

综述

在这篇文章中,Netflix团队将展示如何用你随手可及的Linux命令行工具在60s内完成一次性能问题排查。通过以下10个命令,你可以在60秒内对系统的资源使用率和进程运行状况有个整体的了解。首先查看错误和饱和度指标,因为这两者都很容易理解,其次就是查看资源利用率。饱和度是指资源的负载是否超过了它所能承受的负载,这个指标可以反映出出任务队列长度情况或者是任务等待时间的情况。

uptime
dmesg | tail
vmstat 1
mpstat -P ALL 1
pidstat 1
iostat -xz 1
free -m
sar -n DEV 1
sar -n TCP,ETCP 1
top

注意,有些命令需要安装sysstat包。这些命令暴露出来的数据可以帮你完成一次性能优化方法学的实践,这套方法学包括检查所有系统资源(cpu、内存、磁盘……)的使用率、饱和度和错误指标。这些命令也能让你检查所有的地方,通过排除法缩小排查范围,为后续分析指明方向。

文章接下来的部分会介绍这些命令,并给出实际的例子。关于这些命令更详细的介绍请参考相关手册。

1. uptime

$ uptime 
23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02

uptime可以快速看到系统的平均负载情况。在Linux中,这些数字表示平均每秒钟处于运行态、可执行态和不可中断状态(通常是磁盘IO)的任务数量。这些数据可以让我们对整个系统资源有个整体的认识,但没有其他工具我们依旧没法理解根因,不过uptime依旧很值得快速瞄一眼。

那这三个数字究竟是什么含义呢!其实这三个数字分别表示1分钟、5分钟、15分钟内的平均负载情况,是通过过去某个时间窗口的数据通过指数衰减求和得到的。这三个数字可以让你了解到过去某段时间的负载状况。比如,如果你上线查性能问题,你看到load1远低于load15,那你可能已经错过这次性能问题了。

在上面的例子中,负载一直在增长,load1已经到30了,而load15只有19,这给了我们很重要的信息,有可能是CPU使用率高了,还得用vmstat和mpstat确认下,这两个命令我们会在3和4中介绍。

2. dmesg|tail

$ dmesg | tail
[1880957.563150] perl invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
[...]
[1880957.563400] Out of memory: Kill process 18694 (perl) score 246 or sacrifice child
[1880957.563408] Killed process 18694 (perl) total-vm:1972392kB, anon-rss:1953348kB, file-rss:0kB
[2320864.954447] TCP: Possible SYN flooding on port 7001. Dropping request.  Check SNMP counters.

如果有的话,这条命令将会展示系统最近的10条信息。 找出其中可能导致性能问题的错误。上面这个例子中包含一条因为oom导致进程被kill和tcp丢请求的信息。

不要跳过这步,dmesg非常值得查看。

3. vmstat 1

$ 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
34  0    0 200889792  73708 591828    0    0     0     5    6   10 96  1  3  0  0
32  0    0 200889920  73708 591860    0    0     0   592 13284 4282 98  1  1  0  0
32  0    0 200890112  73708 591860    0    0     0     0 9501 2154 99  1  0  0  0
32  0    0 200889568  73712 591856    0    0     0    48 11900 2459 99  0  0  0  0
32  0    0 200890208  73712 591860    0    0     0     0 15898 4840 98  1  1  0  0
^C

vmstat是有个广泛存在于各类linux系统中的命令(几十年前为BSD所创造的),可以展出虚拟内存相关的概要信息,每一行都是服务器虚拟内存的关键统计信息。

后面的参数1表示每隔1秒输出一次。注意,输出的第一行是自系统启动以来的数据,而不是前一秒的,所以可以跳过第一行数据。

每列的含义

  • r: 正在运行和等待运行的进程数量。这个指标可以比load更好的揭示出CPU的负载情况,因为这里不包含I/O进程。如果r值大于CPU核数说明CPU已经饱和。
  • free: 空闲内存的容量(单位kB),如果数字多的数不清说明你还有很多空闲内存可用。在下文第7条中的free -m命令可以更直观看到空闲内存情况。
  • si,so: swap分区的换进和换出。如果数字不是0说明你内存已经不够了,开始使用swap分区了。
  • us,sy,id,wa,st: 这些是CPU平均使用时长的细致划分,分别是用户时长、系统时长(内核)、空闲时长、等待IO时长、被盗用时长(被其他访客或者Xen盗用,访客有自己独立的驱动域)。

对CPU时间(用户时长+系统时长)的细致划分可以确认CPU是否繁忙。如果等待IO时长搞定不变,说明磁盘IO是瓶颈。这也能解释为什么CPU是空闲的,因为任务都因为等待IO被阻塞掉了。所以你可以将等待I/O看作是CPU空闲的另一种形式,它提供了有关为什么它们是空闲的线索。

对于IO型的进程,系统时长非常重要,如果平均系统时长超过20%就很值得深入探究下了,这可能说明内核IO处理很低效。

上面的例子中,CPU几乎都被用户态所占用,平均CPU利用率也超过90%,这通常没什么大问题,还是重点关注下r这列数据吧。

4. mpstat -P ALL 1

$ mpstat -P ALL 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015  _x86_64_ (32 CPU)

07:38:49 PM  CPU   %usr  %nice   %sys %iowait   %irq  %soft  %steal  %guest  %gnice  %idle
07:38:50 PM  all  98.47   0.00   0.75    0.00   0.00   0.00    0.00    0.00    0.00   0.78
07:38:50 PM    0  96.04   0.00   2.97    0.00   0.00   0.00    0.00    0.00    0.00   0.99
07:38:50 PM    1  97.00   0.00   1.00    0.00   0.00   0.00    0.00    0.00    0.00   2.00
07:38:50 PM    2  98.00   0.00   1.00    0.00   0.00   0.00    0.00    0.00    0.00   1.00
07:38:50 PM    3  96.97   0.00   0.00    0.00   0.00   0.00    0.00    0.00    0.00   3.03
[...]

这个命令把每个CPU核的细致划分出来,从这份数据中可以看出CPU核心负载是否均衡,如果单个CPU核心出现热点说明有单线程的应用。

5. pidstat 1

$ pidstat 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015    _x86_64_    (32 CPU)

07:41:02 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
07:41:03 PM     0         9    0.00    0.94    0.00    0.94     1  rcuos/0
07:41:03 PM     0      4214    5.66    5.66    0.00   11.32    15  mesos-slave
07:41:03 PM     0      4354    0.94    0.94    0.00    1.89     8  java
07:41:03 PM     0      6521 1596.23    1.89    0.00 1598.11    27  java
07:41:03 PM     0      6564 1571.70    7.55    0.00 1579.25    28  java
07:41:03 PM 60004     60154    0.94    4.72    0.00    5.66     9  pidstat

07:41:03 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
07:41:04 PM     0      4214    6.00    2.00    0.00    8.00    15  mesos-slave
07:41:04 PM     0      6521 1590.00    1.00    0.00 1591.00    27  java
07:41:04 PM     0      6564 1573.00   10.00    0.00 1583.00    28  java
07:41:04 PM   108      6718    1.00    0.00    0.00    1.00     0  snmp-pass
07:41:04 PM 60004     60154    1.00    4.00    0.00    5.00     9  pidstat
^C

pidstat有点像top命令关于每个进程的统计,和top命令不同的是它是滚动输出而不是清屏输出,这种模式可以很方便看过去的变化情况,也可以很方便的复制粘贴在你排查过程中。

上面的例子中,有两个java进程消耗了大量的CPU,1591%说明这个java进程占用了将近16个核心。

6. iostat -xz 1

$ iostat -xz 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015  _x86_64_ (32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          73.96    0.00    3.73    0.03    0.06   22.21

Device:   rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda        0.00     0.23    0.21    0.18     4.52     2.08    34.37     0.00    9.98   13.80    5.42   2.44   0.09
xvdb        0.01     0.00    1.02    8.94   127.97   598.53   145.79     0.00    0.43    1.78    0.28   0.25   0.25
xvdc        0.01     0.00    1.02    8.86   127.79   595.94   146.50     0.00    0.45    1.82    0.30   0.27   0.26
dm-0        0.00     0.00    0.69    2.32    10.47    31.69    28.01     0.01    3.23    0.71    3.98   0.13   0.04
dm-1        0.00     0.00    0.00    0.94     0.01     3.78     8.00     0.33  345.84    0.04  346.81   0.01   0.00
dm-2        0.00     0.00    0.09    0.07     1.35     0.36    22.50     0.00    2.55    0.23    5.62   1.78   0.03
[...]
^C

iostat是查看块设备负载和性能信息最好用的工具,可以查看以下信息:

  • r/s, w/s, rkB/s, wkB/s: 设备每秒的读、写次数和读、写数据量(kB)。这些指标可以量化IO设备负载,有些性能问题可能就是因为负载过高导致的。
  • await: 等待IO的毫秒数。这是应用程序所感受到的时间,包括排队时间和等待时间。如果超过平均预期时间说明设备已饱和或者设备故障。
  • avgqu-sz: 设备的平均请求数。如果值大于1可能是设备已饱和(尽管设备通常可以并行操作请求,特别是位于多个后端磁盘前的虚拟设备)。
  • %util: 设备的使用率。这是设备真实忙碌的时间比例,展示了每秒设备实际工作的时间。超过60%可能导致设备性能降低,当然这也取决于设备自身。接近100%说明设备已经饱和了。

如果存储设备只是由多块磁盘组成的逻辑设备,100%的利用率也仅仅意味着100%的时间用来处理IO了,后端物理磁盘远远没有达到它们所能处理的性能极限。

请记住,磁盘I/O性能差不一定导致应用程序出问题。许多技术通常使用了异步I/O,这样应用程序就不会被阻塞也感受不到延迟(例如,预读和写Buffer)。

7. free -m

$ free -m
             total       used       free     shared    buffers     cached
Mem:        245998      24545     221453         83         59        541
-/+ buffers/cache:      23944     222053
Swap:            0          0          0

最右边有两列buffers和cached

  • buffers: 缓冲区,用于块设备IO。
  • cached: 内存页缓存,用在文件系统。

我们只需要检查下它们的大小是否接近于0,接近0可能导致更高的磁盘I/O(使用iostat进行确认)和更差的性能。上面的例子看起来很好,每一项都有很多兆。

“-/+ buffers/cache” 为已使用和空闲内存大小提供了明确的值。linux用空闲内存作为cache,如果应用需要更多内存也可以很快释放掉,所以cached部分的内存也应当包含在free列里,这一行数据就是这样,这里可能让人摸不着头脑,更详细内容可以查看这个网页linuxatemyram.com/

如果linux系统用了ZFS会更让人迷惑,因为ZFS有自己的文件系统缓存,free -m 并不能反映出这些文件缓存的大小。所以可能出现看起来内存不足,但实际上可以按需从ZFS cache里释放一些内存。

8. sar -n DEV 1

$ sar -n DEV 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015     _x86_64_    (32 CPU)

12:16:48 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
12:16:49 AM      eth0  18763.00   5032.00  20686.42    478.30      0.00      0.00      0.00      0.00
12:16:49 AM        lo     14.00     14.00      1.36      1.36      0.00      0.00      0.00      0.00
12:16:49 AM   docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

12:16:49 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
12:16:50 AM      eth0  19763.00   5101.00  21999.10    482.56      0.00      0.00      0.00      0.00
12:16:50 AM        lo     20.00     20.00      3.25      3.25      0.00      0.00      0.00      0.00
12:16:50 AM   docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
^C

这个命令可以查看网络吞吐量,rxkB/s和txkB/s,可以度量工作负载,也可以查看是否达到了限制。在上面的例子中,eth0接收达到了22MB/s,也就是176Ms/S(远低于1Gb/s的限制)。
这个版本也有个%ifutil来表示设备利用率(全双工的两个方向的最大值),我们用Brendan的nicstat也可以查看。就像使用nicstat一样,很难得到正确的结果,而且在本例中似乎不能正常工作(0.00)。

9. sar -n TCP,ETCP 1

$ sar -n TCP,ETCP 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015    _x86_64_    (32 CPU)

12:17:19 AM  active/s passive/s    iseg/s    oseg/s
12:17:20 AM      1.00      0.00  10233.00  18846.00

12:17:19 AM  atmptf/s  estres/s retrans/s isegerr/s   orsts/s
12:17:20 AM      0.00      0.00      0.00      0.00      0.00

12:17:20 AM  active/s passive/s    iseg/s    oseg/s
12:17:21 AM      1.00      0.00   8359.00   6039.00

12:17:20 AM  atmptf/s  estres/s retrans/s isegerr/s   orsts/s
12:17:21 AM      0.00      0.00      0.00      0.00      0.00
^C

这个命令可以查看tcp指标数据,包括:

  • active/s: 每秒钟本地发起的主动连接数(比如调用 connect())。
  • passive/s: 每秒钟收到的远程被动连接数(比如调用accept())。
  • retrans/s: 每秒钟tcp重传数。

主动和被动连接数通常可以作为服务器负载的粗略度量:新接受连接的数量(被动)和下游连接的数量(主动)。可以简单将active视为出,将passive视为入,但这并不完全正确(例如,localhost发起到localhost的连接)。
重传数可以看做是网络或者服务问题的一个信号,可能是网络不可靠(比如公网),或者是因为服务已经过载而导致的丢包。上面这个例子中每秒只有一个新建连接。

10. top

$ top
top - 00:15:40 up 21:56,  1 user,  load average: 31.09, 29.87, 29.92
Tasks: 871 total,   1 running, 868 sleeping,   0 stopped,   2 zombie
%Cpu(s): 96.8 us,  0.4 sy,  0.0 ni,  2.7 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:  25190241+total, 24921688 used, 22698073+free,    60448 buffers
KiB Swap:        0 total,        0 used,        0 free.   554208 cached Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 20248 root      20   0  0.227t 0.012t  18748 S  3090  5.2  29812:58 java
  4213 root      20   0 2722544  64640  44232 S  23.5  0.0 233:35.37 mesos-slave
 66128 titancl+  20   0   24344   2332   1172 R   1.0  0.0   0:00.07 top
  5235 root      20   0 38.227g 547004  49996 S   0.7  0.2   2:02.74 java
  4299 root      20   0 20.015g 2.682g  16836 S   0.3  1.1  33:14.42 java
     1 root      20   0   33620   2920   1496 S   0.0  0.0   0:03.82 init
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.02 kthreadd
     3 root      20   0       0      0      0 S   0.0  0.0   0:05.35 ksoftirqd/0
     5 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
     6 root      20   0       0      0      0 S   0.0  0.0   0:06.94 kworker/u256:0
     8 root      20   0       0      0      0 S   0.0  0.0   2:38.05 rcu_sched

top命令中包含很多我们前面已经提到过的指标,可以方便地运行它来查看指标的变化。
top的一个缺点是,top不像vmstat和pidstat等提供滚动输出的工具一样,它看不到之前的数据。如果你没有足够快地暂停输出(Ctrl-S暂停,Ctrl-Q继续),屏幕上的数据就会被清除,你很难截取到证据。

后续分析

还有很多命令行工具和方法可以深入挖掘,参见Brendan的Linux性能工具指南,里面列出了超过40种工具,包含了观测、基准测试、调优、静态性能调优、概要分析和追踪。

登录 后评论
下一篇
云栖号资讯小编
771人浏览
2020-03-31
相关推荐
C#性能优化实践
743人浏览
2017-11-08 17:16:00
Linux 性能分析的前 60 秒
978人浏览
2017-05-02 15:43:00
Linux环境下网络性能测试
1153人浏览
2017-10-09 15:37:00
C#性能优化实践
683人浏览
2012-07-18 16:01:00
性能测试之吞吐量
506人浏览
2015-01-25 19:03:00
0
0
0
165