原文链接:https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55。本文只是处于学习目的,转载请注明,翻译水平有限。
Linux性能分析60秒
当你登录到一台有性能问题的Linux服务器上时,前1分钟你该检查什么?
Netflix有大量的EC2Linux云主机,并且有大量的性能分析工具来监控和检查服务器的性能。包括云层面监控的Atlas和根据需求进行实例分析的Vector。虽然这些工具能帮助我们分析很多问题,但有时我们需要登录的主机实例上运行标准的Linux性能工具。
First 60 Seconds: Summary前60秒总览
Netflix性能工程师团队将展示在检查性能的前60秒使用的命令行。在这60秒钟你可以使用下面的10个命令得到系统资源使用和运行进程的总览情况。使用这些命令首先要检查错误,查看饱和度指标,因为这两项很好解释,接着是资源的使用率。饱和度是一项资源负载较大,超过了其处理能力,通常会以请求队列的长度或等待时间的方式来展示。
使用到的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
方法的需求:USE
是用于定位性能瓶颈的方法论。它包括检查所有资源(CPU,MEM,Disk等)的使用率,饱和度,和错误事件。
接下来是这些命令在生产系统的使用示例,这些工具的详情可以通过man手册查询。
1 uptime
$ uptime
23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02
这是查看系统平局负载的快速方式,平均负载显示了系统当前想要运行的进程数量。在Linux系统中,这个数值包含即将运行的进程数量和不可终端IO进程数量。这个给出了一个较高层面的资源负载情况。如果不借助其他工具,对此种负载情况并不能产生正确的理解。
在上面的示例中,平均负载在增加。数值很大,意味着很多东西:可能是CPU需求增加。使用vmstat
或mpstat
命令可以进一步确认具体情况。
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-killer和TCP dropping a request。
千万不能错过这一步,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(8)是一个通用的工具(十几年前为BSD系统首次创建)。此工具会输出服务器关键统计信息总览。
vmstat的参数1,表示每1秒的总体情况。在输出的列中,有些是自开机以来的平均值,而不是前一秒的情况。现在让我们跳过第一行,除非你想记住每一列是什么。
需要检查的列
- r: 等待CPU运行的数量。这对于确定CPU饱和度比平均负载提供了更好的信息。因为此列不包含IO。解释:如果r的值大于CPU的数量,则说明CPU饱和了
- free:以KB为单位的free 内存数量,如果数值很大,可以使用free -m命令
- si,so:Swap-ins and swap-outs。如果这些值不会0,则说明内存用完了。
- us, sy, id, wa, st: 这几项将CPU时间分解,是所有CPU的平均值。分别代表user time,system time(kernel),idle,wait I/O,stolen time(by other guests, or with Xen, the guest’s own isolated driver domain)
如果CPU繁忙,则CPU分解可以通过user time + system time确定。对于disk瓶颈,则wait I/O是个常数。因为task因为等待pending状态的disk I/O而阻塞,则此时CPU处于idle状态。你可以将等待I/O视为另一种形式的CPU idle状态,这可以给出一个提示,为什么CPU处于idle状态。
system time对于I/O处理是必须的。较高的平均系统时间,超过20%,就应该深入检查一下:可能kernel正在处理低效的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的每个进程的概览情况有点相似,但输出的是一个滚动的概览情况,而不是在屏幕动态显示。这对在一段时间内观察非常有帮助,同时也支持将你看到的记录的你的调查中(copy-n-paste)
上面的示例表明主要是两个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
iostat是用于理解块设备(磁盘)的强大工具,它涵盖了应用负载和性能结果。检查下面几项:
- r/s, w/s, rkB/s, wkB/s:设备每秒传递的读,写,读KB,写KB。使用这些指标进行工作负载排查。性能问题可能是因为一个过度使用的负载应用。
- await:用于I/O的平均时间,毫秒。这是应用程序经历的时间,包括队列等待和被服务的时间。如果大于期望的平均时间则表明设备饱和了或者设备有问题了
- avgqu-sz:发给设备的平均请求数量。值大于1则表明设备饱和了(尽管设备对请求的典型操作可以并行进行,尤其是虚拟设备,处于多个后端磁盘的前端)
- %util:设备使用率。如果是个繁忙的百分比,则表示设备每秒都在工作。尽管取决于设备,但值如果大于60%,一般会导致较差的性能(这可以在await中看到)。值接近100%一般代码饱和了。
如果存储设备是个逻辑磁盘设备,位于多个后端磁盘的前面,则100%的使用率仅表明一些I/O正在被处理,占用100%的时间,但后端的磁盘离饱和还很远呢,并可以处理更多的工作。
需要记住的是较差的disk I/O性能并不是应用问题的必要条件。有许多技术可以用来进行I/O异步操作,因此应用并不会阻塞,也不会直接忍受延迟(比如read-ahead for reads, and buffering for writes).
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:buffer cache,used for block device I/O
- cached: page cache, used by file systems
我们需要检查它们的大小不接近0,因为那样可能导致较高的磁盘I/O(通过iostat确认),和较差的性能。上面的示例看起来还不错,每个都有很多MB。
“-/+ buffers/cache”用于使用的和空闲的内存并不会带来很强的混淆。Linux使用空闲内存用于cache,如果应用需要,cache可以被快速回收。因此cached的内存应该包含在空闲内存一栏。网站有关于这个问题的描述。
如果在Linux上使用ZFS,则会进一步混淆。因为ZFS有其自己独立的文件系统cache,因此free -m并不能直接正确的反应出来。
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 and txkB/s指标用于测量工作负载。另外还要检查是否达到了某些限制。上面的示例中,eth0接受达到了22 Mbytes/s,即176Mbits/sec (well under, say, a 1 Gbit/sec limit可以说在1 Gbit/sec limit内)
这个版本有%ifutil一列,用于表示设备使用率(max of both directions for full duplex),这项有时有采用Brendan’s nicstat tool工具测量。
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每秒重传数量
active和passive计数对于粗略的测量服务器负载是比较有用的:新accepted连接数(passive),下游连接数(active)。可以将active视为出口流量,passive视为进入流量。但这并不是严格的准确(如localhost到localhost的连接)
重传是网络问题或服务器问题的信号;可能是网络不稳定(如公网),或服务器因为过载而丢包。上面的示例显示每秒仅有一个新的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很容易看到前面命令查找的指标,哪个负载在变化。top不好的地方在于很难在一个时间段内找到规律。但这对于vmstat和pidstat工具来说是非常容易的。如果你不能够快速的暂停输出(Ctrl-S to pause, Ctrl-Q to continue),则很容易存过中间的可能的有用信息。
Follow-on Analysis
还有更多的工具和方法等待你去发掘和使用。参见Brendan在 Velocity 2015分享的Linux Performance Tools tutorial,本次分享涉及到了40多个命令,包含observability, benchmarking, tuning, static performance tuning, profiling, and tracing。
Reference
- https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55
- https://netflixtechblog.com/netflix-at-velocity-2015-linux-performance-tools-51964ddb81cf