Linux 入门必看:如何60秒内分析Linux性能
来源:腾讯技术工程

当你登陆一台 Linux 服务器之后,因为一个问题要做性能分析时:你会在第 1 分钟内做哪些检测呢?
在 Netflix,我们有很多 EC2 的 Linux 机器,并且也需要很多性能分析工具来监控和检查它们的性能。包括有针对云上的监控工具 Atlas,和按需要进行实例分析的 Vector。虽然这些工具能帮助我们解决大多数问题,但是我们有时候还需要登陆机器实例去运行一些标准的 Linux 性能分析工具。
最开始的 60 秒:总结在这篇文章中,Netflix 的性能分析工程师团队会给你展示在最开始的 60 秒内,如何在命令行模式下使用已有的 Linux 标准工具进行性能优化检测。在 60 秒内只需要通过运行下面的 10 个命令就可以对系统资源使用和运行进程有一个很高程度的了解。寻找错误信息和饱和度指标,并且可以显示为请求队列的长度,或者等待时长。因为它们都很容易理解,然后就是资源利用率。饱和度是指一个资源已经超过了它自己的负荷能力。
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(Utilization,Saturation,Errors) 方法:定位性能瓶颈的方法论。包括了检查使用率(Utilization),饱和度(Saturation),所有资源(比如 CPU,内存,磁盘等)的错误指标(Errors)。同样也要关注你什么时候检查和排除一个资源问题,因为通过排除可以缩小分析范围,同时也指导了任何后续的检查。
    下面的章节将会通过一个生产系统中的例子来介绍这些命令。要了解更多这些工具的信息,也可以查看它们的帮助手册。
    1. uptime
    $ uptime
  • 23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02
  • 复制代码
    这是一个快速展示系统平均负载的方法,这也指出了等待运行进程的数量。在 Linux 系统中,这些数字包括等待 CPU 运行的进程数,也包括了被不可中断 I/O(通常是磁盘 I/O)阻塞的进程。这给出了资源负载的很直接的展示,可以在没有其它工具的帮助下更好的理解这些数据。它是唯一快捷的查看系统负载的方式。
    这三个数字是以递减的方式统计了过去 1 分钟,5 分钟和 15 分钟常数的平均数。这三个数字给我们直观展示了随着时间的变化系统负载如何变化。例如,如果你被叫去查看一个有问题的服务器,并且 1 分钟的所代表的值比 15 分钟的值低很多,那么你可能由于太迟登陆机器而错过了问题发生的时间点。
    在上面的例子中,平均负载显示是在不断增加的,1 分钟的值是 30,相比 15 分钟的值 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 问题的进程,丢弃 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 是一个常用工具(最早是几十年前为 BSD 创建的)。它每一行打印关键的服务信息统计摘要。
    vmstat 使用参数 1 来运行的时候,是每 1 秒打印一条统计信息。在这个版本的 vmstat 中,输出的第一行展示的是自从启动后的平均值,而不是前一秒的统计。所以现在,可以跳过第一行,除非你要看一下抬头的字段含义。
    每列含义说明:

    • r: CPU 上的等待运行的可运行进程数。这个指标提供了判断 CPU 饱和度的数据,因为它不包含 I/O 等待的进程。可解释为:“r” 的值比 CPU 数大的时候就是饱和的。
    • free:空闲内存,单位是 k。如果这个数比较大,就说明你还有充足的空闲内存。“free -m” 和下面第 7 个命令,可以更详细的分析空闲内存的状态。
    • si,so:交换进来和交换出去的数据量,如果这两个值为非 0 值,那么就说明没有内存了。
    • us,sy,id,wa,st:这些是 CPU 时间的分解,是所有 CPU 的平均值。它们是用户时间,系统时间(内核),空闲,等待 I/O 时间,和被偷的时间(这里主要指其它的客户,或者使用 Xen,这些客户有自己独立的操作域)。
    CPU 时间的分解可以帮助确定 CPU 是不是非常忙(通过用户时间和系统时间累加判断)。持续的 I/O 等待则表明磁盘是瓶颈。这种情况下 CPU 是比较空闲的,因为任务都由于等待磁盘 I/O 而被阻塞。你可以把等待 I/O 看作是另外一种形式的 CPU 空闲,而这个命令给了为什么它们空闲的线索。
    系统时间对于 I/O 处理来说是必须的。比较高的平均系统时间消耗,比如超过了 20%,就有必要进一步探索分析了:也有可能是内核处理 I/O 效率不够高导致。
    在上面的例子中,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 命令中的为每个 CPU 统计信息功能,但是它是以不断滚动更新的方式打印信息,而不是每次清屏打印。这个对于观察随时间变化的模式很有用,同时把你看到的信息(复制粘贴)记到你的调查记录中。
    上面的例子可以看出是 2 个 java 进程在消耗 CPU。%CPU 列是所有 CPU 的使用率;1591% 是说明这个 java 进程消耗了几乎 16 个 CPU 核。
    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
  • 复制代码
    这个工具对于理解块设备(比如磁盘)很有用,展示了请求负载和性能数据。具体的数据看下面字段的解释:

    • r/s, w/s, rkB/s, wkB/s:这些表示设备上每秒钟的读写次数和读写的字节数(单位是 k 字节)。这些可以看出设备的负载情况。性能问题可能就是简单的因为大量的文件加载请求。
    • await:I/O 等待的平均时间(单位是毫秒)。这是应用程序所等待的时间,包含了等待队列中的时间和被调度服务的时间。过大的平均等待时间就预示着设备超负荷了或者说设备有问题了。
    • avgqu-sz:设备上请求的平均数。数值大于 1 可能表示设备饱和了(虽然设备通常都是可以支持并行请求的,特别是在背后挂了多个磁盘的虚拟设备)。
    • %util:设备利用率。是使用率的百分数,展示每秒钟设备工作的时间。这个数值大于 60% 则会导致性能很低(可以在 await 中看),当然这也取决于设备特点。这个数值接近 100% 则表示设备饱和了。
    如果存储设备是一个逻辑磁盘设备,后面挂载了多个磁盘,那么 100% 的利用率则只是表示有些 I/O 是在 100% 处理,然而后端的磁盘或许远远没有饱和,还可以处理更多的请求。
    请记住,磁盘 I/O 性能低不一定是应用程序的问题。许多技术通常都被用来实现异步执行 I/O,所以应用程序不会直接阻塞和承受延时(比如:预读取和写缓冲技术)。
    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:用于块设备 I/O 缓冲的缓存。
    • cached:用于文件系统的页缓存。
    我们只想检测这些缓存的数值是否接近 0 。不为 0 的可能导致较高的磁盘 I/O(通过 iostat 命令来确认)和较差的性能问题。上面的例子看起来没问题,都还有很多 M 字节。
    “-/+ buffers/cache” 这一行提供了对已使用和空闲内存明确的统计。Linux 用空闲内存作为缓存,如果应用程序需要,可以快速拿回去。所以应该包含空闲内存那一列,这里就是这么统计的。甚至有一个网站专门来介绍 Linux 内存消耗的问题:linuxatemyram
    如果在 Linux 上使用了 ZFS 文件系统,则可能会更乱,因为当我们在开发一些服务的时候,ZFS 有它自己的文件系统缓存,而这部分内存的消耗是不会在 free -m 这个命令中合理的反映的。显示了系统内存不足,但是 ZFS 的这部分缓存是可以被应用程序使用的。
    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 接收数据达到 22 M 字节/秒,也就是 176 Mbit/秒(网卡的上限是 1 Gbit/秒)。
    这个版本的工具还有一个统计字段: %ifutil,用于统计设备利用率(全双工双向最大值),这个利用率也可以使用 Brendan 的 nicstat 工具来测量统计。在这个例子中 0.00 这种情况就似乎就是没有统计,这个和 nicstat 一样,这个值是比较难统计正确的。
    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:每秒本地发起的 TCP 连接数(例如通过 connect() 发起的连接)。
    • passive/s:每秒远程发起的连接数(例如通过 accept() 接受的连接)。
    • retrans/s:每秒 TCP 重传数。
    这种主动和被动统计数通常用作对系统负载的粗略估计:新接受连接数(被动),下游连接数(主动)。可以把主动看作是外部的,被动的是内部,但是这个通常也不是非常准确(例如:当有本地到本地的连接时)。
    重传是网络或者服务器有问题的一个信号;可能是一个不可靠的网络(例如:公网),或者可能是因为服务器过载了开始丢包。上面这个例子可以看出是每秒新建一个 TCP 连接。
    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 的一个缺陷也比较明显,很难看出变化趋势,其它像 vmstat 和 pidstat 这样的工具就会很清晰,它们是以滚动的方式输出统计信息。所以如果你在看到有问题的信息时没有及时的暂停下来(Ctrl-S 是暂停, Ctrl-Q 是继续),那么这些有用的信息就会被清屏。
    Follow-on Analysis还有很多可以使用来深挖系统问题的命令和技术,可以看看 Brendan 在 2015 年讲的 Linux 性能工具介绍 ,这里面讲述了 40 多个命令,涵盖了可观测性,基准测试,调优,静态性能调优,分析和跟踪等多个方面。
    原文链接:https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55
    作者:helightxu,腾讯 IEG 开发工程师