1分钟Linux性能分析

最近看ebpf相关技术,找到一篇2015年的老文,现在看依然不过时——原文

当你为了性能问题而登录到Linux系统时,首先要检查哪些东西呢?

在奈飞有大量的Linux机器,并且有众多的工具去监控和分析性能。既包括负责整个云范围的监控工具Atlas,也包括单个实例分析的Vector。尽管这些工具帮助我们解决了很多问题,但是有些时候我们还是需要登录到实例上去执行一些标准Linux指令。

1分钟:总览

在本文,奈飞性能工程团队将展示1分钟内使用标准Linux命令行工具进行性能优化分析相关操作。通过运行以下10个命令,您可以在1分钟内对系统资源使用和运行的进程有一个大致的了解。关注错误、饱和度指标、资源利用率,因为他们都很直观。饱和度是指资源的负载超过了它的处理能力,并且可以通过为请求队列的长度或等待的时间来反映:

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包,这些命令获取的值将帮助您完成一些 USE Method:一种定位性能瓶颈的方法。这包括检查所有资源(cpu、内存、磁盘等)的利用率、饱和度和错误度量。也要注意你什么时候检查和排除了一个资源,因为通过排除的过程,这缩小了研究的目标,并指导任何后续的调查。

下面几节总结了这些命令,并提供了来自生产系统的示例。有关这些工具的更多信息,请使用man命令。

uptime

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

这个命令可以方便的查看系统平均负载,平均负载表明来需要运行的任务(进程)的数量。在Linux中,这些数字包含了想在CPU上运行的进程,也包含了哪些阻塞在不可中断I/O的进程(通常是磁盘I/O)。这提供了资源负载(或需求)的整体状况,但如果没有其他工具,就无法正确理解细节,简单看一下就行了。

后面的3个数字分别是指1分钟、5分钟、15分钟的移动平均值。这3个数字告诉我们负载是如何随着时间变化的。如果你去检查一个服务器问题,1分钟的🈯值远远低于15分钟的值,那么你很有可能登录的太晚而错过了问题。

上面的例子中,1分钟的值是30而15分钟的值是19,前者数值较大很可能是CPU比较繁忙,使用vmstat或者mpstat可以用来证实这个猜想,我们将在后面的章节讲解。

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-killer,以及tcp丢弃了一个请求。

不要遗漏这一步,这步非常有价值!

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是 “virtual memory stat” 的缩写,一个很常用的工具(由BSD十几年前开发),它在每一行打印了一些服务器关键统计指标。

后面的参数1是指每1秒钟打印一次,这个版本里的第一行可以忽略掉没,触发你想学习并背下哪一列是什么。

重点检查:

  1. r:CPU上运行并等待轮询的进程数。这为确定CPU饱和提供了比平均负载更好的指标,因为它不包含I/O。解释:“r"的值大于CPU数量就是过载。
  2. free:空闲内存,单位KB。这个数字越大,说明可用内存越充足。下面讲的free -m命令对内存有更详细的解释。
  3. si,so:swap-ins和swap-out,如果这个不为0,表明内存不够用了。
  4. us,sy,id,wa,st:是所有CPU的时间占用平均指标,分别是用户占用时间(user time)、系统/内核占用时间(system time)、空间时间(idle)、等待I/O的时间(wait I/O)、被盗用的时间(stolen,被其他虚拟机、或者xen中虚拟机有独立的驱动域)。

通过us+sy可以来确定CPU是否繁忙,wa则可以用来磁盘是否有性能瓶颈,wa高时通常CPU比较空间,因为任务都被阻塞在等待磁盘I/O上。你可以把这个当作另一种CPU空闲指标,这给出了CPU空闲的一个原因。

sy对于I/O也是必要的,如果sy值特别高,超过20%,可以更进一步的去排查:可能内核处理I/O效率低下。

上面的例子中,CPU时间几乎都在用户态,表明大部分是被应用程序使用了。CPU平均使用率也超过了90%,这不一定是个问题,需要结合"r"列来一起看。

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使用率过高,可以作为是某个单线程应用程序的证据。

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命令的每个进程的概览,只不过是通过循环打印而不是清理屏幕再输出的方式。这对于长期观察很有用,可以将所看到的(复制粘贴)记录到调查记录中。

上面的例子显示有2个java应用占用了大量的CPU,%CPU列是全部CPU的使用,1591%表明这个java进程几乎使用了16个CPU。

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

这是理解块设备(磁盘)、应用的工作负载和最终的性能的一个很好的工具。

  • r/s, w/s, rkB/s, wkB/s:这个指磁盘每秒读写的数据量,用来描述工作负载,性能问题可能是由于很简单的负载过高导致。
  • await:I/O的平均时间,以毫秒为单位。这是应用程序受到影响的时间,因为它既包括排队的时间,也包括正在服务的时间。超过预期的平均时间可能表明设备负载过高或设备有问题。
  • avgqu-sz:向设备发出的请求的平均数量。大于1可能表明负载过高(尽管设备通常可以并行操作请求,特别是前端有多个后端磁盘的虚拟设备)。
  • %util:设备利用率。用来描述设备是否繁忙,显示设备每秒工作的时间。值大于60%通常会导致较差的性能(应该在await中看到),尽管这取决于设备。接近100%的值通常表示过载。

如果存储设备是一个有许多后端磁盘的逻辑磁盘设备,那么100%的利用率可能仅仅意味着某些I/O的处理时间是100%,然而后端磁盘可能远未饱和,可能能够处理更多的工作。

记住,性能较差的磁盘I/O不一定是应用程序的问题。许多技术通常使用异步I/O,这样应用程序就不会阻塞或被I/O延迟影响(例如预读或写缓存)。

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

关注2列:

  • buffers:缓冲区buffer cache,和块设备I/O相关。
  • cached:页缓存page cache,和文件系统相关。

我们只是想检查它们的大小是否接近于零,接近零会导致更高的磁盘I/O(使用iostat进行确认)和更差的性能。上面的例子看起来很好,每个都有很多mb。

-/+ buffers/cache看起来让人很困惑,Linux使用空闲内存作为缓存,当应用程序需要时可以快速回收。因此,在某种程度上,缓存的内存应该包含在空闲内存列中,这一行就是这么做的。

如果在Linux上使用了ZFS(就像我们在某些服务中所做的那样),还会造成另外的困惑,因为ZFS有自己的文件系统缓存,而这个缓存没有被空闲的-m列正确地反映出来。可能会出现系统空闲内存不足的情况,而实际上该内存可以根据需要从ZFS缓存中使用。

(Roy友情提示,free -m 命令在新版中输出已经变了,buffer和cached被合并且多了个available。)

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达到了22MBytes/s的接收,换算为176Mbits/s,远低于1Gbit/s的限制。(Roy友情提示,看网络指标时候一定注意单位)

这个版本还有%ifutil用于设备利用率(全双工的最大两个方向),我们也使用Brendan的nicstat工具来测量这个值。

和nicstat一样,很难得到正确的结果,在本例中似乎不起作用(0.00)。

(Roy友情提示,新版已经没有%ifutil这个了。)

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: 每秒本地发起的TCP连接数(比如connect()函数)。
  • passive/s: 每秒远端发起的TCP连接数(比如accept()函数)。
  • retrans/s: 每秒TCP重传次数.

active和passive通常用来粗略衡量服务负载:被动建立的连接数(passive)和主动发起的连接数(active)。把active视为出站流量把passive视为入站流量,但并不完全精确。(比如localhost向localhost的连接)

重传数量是网络或者服务有问题的标志,也许是访问里一个不可达网络(比如公网),也许由于服务负载过大导致丢包。上面的例子中显示每秒有一个新的TCP连接简建立。

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 Performance Tools tutorial,里面讲述了40多款命令,包括可观察性、基准测试、调优、静态性能调优、分析和跟踪。