为了解决性能问题,你登入了一台 linux 服务器,在最开始的一分钟内需要查看什么?
在这篇文章里,netflix performance engineering 团队将使用居家常备的 linux 标准命令行工具,演示在性能调查最开始的60秒里要干的事,
<a></a>
运行下面10个命令,你可以在60秒内就对系统资源的使用情况和进程的运行状况有大体上的了解。无非是先查看错误信息和饱和指标,再看下资源的使用量。这里“饱和”的意思是,某项资源供不应求,已经造成了请求队列的堆积,或者延长了等待时间。
<code>uptime</code>
<code>dmesg | tail</code>
<code>vmstat 1</code>
<code>mpstat -p all 1</code>
<code>pidstat 1</code>
<code>iostat -xz 1</code>
<code>free -m</code>
<code>sar -n dev 1</code>
<code>sar -n tcp,etcp 1</code>
<code>top</code>
接下来的章节里我们将结合实际例子讲解这些命令。如果你想了解更多的相关信息,请查看它们的 man page。
<code>$ uptime</code>
<code>23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02</code>
这个命令显示了要运行的任务(进程)数,通过它能够快速了解系统的平均负载。在 linux 上,这些数值既包括正在或准备运行在 cpu 上的进程,也包括阻塞在不可中断 i/o(通常是磁盘 i/o)上的进程。它展示了资源负载(或需求)的大致情况,不过进一步的解读还有待其它工具的协助。对它的具体数值不用太较真。
最右的三个数值分别是1分钟、5分钟、15分钟系统负载的移动平均值。它们共同展现了负载随时间变动的情况。举个例子,假设你被要求去检查一个出了问题的服务器,而它最近1分钟的负载远远低于15分钟的负载,那么你很可能已经扑了个空。
在上面的例子中,负载均值最近呈上升态势,其中1分钟值高达30,而15分钟值仅有19。这种现象有许多种解释,很有可能是对 cpu 的争用;该系列的第3个和第4个命令——<code>vmstat</code>和<code>mpstat</code>——可以帮助我们进一步确定问题所在。
<code>$ dmesg | tail</code>
<code>[1880957.563150] perl invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0</code>
<code>[...]</code>
<code>[1880957.563400] out of memory: kill process 18694 (perl) score 246 or sacrifice child</code>
<code>[1880957.563408] killed process 18694 (perl) total-vm:1972392kb, anon-rss:1953348kb, file-rss:0kb</code>
<code>[2320864.954447] tcp: possible syn flooding on port 7001. dropping request. check snmp counters.</code>
这个命令显示了最新的10个系统信息,如果有的话。注意会导致性能问题的错误信息。上面的例子里就包括对过多占用内存的某进程的死刑判决,还有丢弃 tcp 请求的公告。
不要漏了这一步!检查<code>dmesg</code>总是值得的。
<code>$ vmstat 1</code>
<code>procs ---------memory---------- ---swap-- -----io---- -system-- ------cpu-----</code>
<code>r b swpd free buff cache si so bi bo in cs us sy id wa st</code>
<code>34 0 0 200889792 73708 591828 0 0 0 5 6 10 96 1 3 0 0</code>
<code>32 0 0 200889920 73708 591860 0 0 0 592 13284 4282 98 1 1 0 0</code>
<code>32 0 0 200890112 73708 591860 0 0 0 0 9501 2154 99 1 0 0 0</code>
<code>32 0 0 200889568 73712 591856 0 0 0 48 11900 2459 99 0 0 0 0</code>
<code>32 0 0 200890208 73712 591860 0 0 0 0 15898 4840 98 1 1 0 0</code>
<code>^c</code>
<code>vmstat(8)</code>,是 “virtual memory stat” 的简称,几十年前就已经包括在 bsd 套件之中,一直以来都是居家常备的工具。它会逐行输出服务器关键数据的统计结果。
通过指定1作为 vmstat 的输入参数,它会输出每一秒内的统计结果。(在我们当前使用的)vmstat 输出的第一行数据是从启动到现在的平均数据,而不是前一秒的数据。所以我们可以跳过第一行,看看后面几行的情况。
检查下面各列:
r:等待 cpu 的进程数。该指标能更好地判定 cpu 是否饱和,因为它不包括 i/o。简单地说,r 值高于 cpu 数时就意味着饱和。
free:空闲的内存千字节数。如果你数不清有多少位,就说明系统内存是充足的。接下来要讲到的第7个命令,<code>free -m</code>,能够更清楚地说明空闲内存的状态。
si,so:交换分区换入和换出。如果它们不为零,意味着内存已经不足,开始动用交换空间的存粮了。
us,sy,id,wa,st:它们是所有 cpu 的使用百分比。它们分别表示 用户态用时user time,系统态用时system time(处于内核态的时间),空闲idle,i/o 等待wait i/o和偷去的时间steal time(被其它租户,或者是租户自己的 xen 隔离设备驱动域isolated driver domain所占用的时间)。
通过相加 us 和 sy 的百分比,你可以确定 cpu 是否处于忙碌状态。一个持续不变的 i/o 等待意味着瓶颈在硬盘上,这种情况往往伴随着 cpu 的空闲,因为任务都卡在磁盘 i/o 上了。你可以把 i/o 等待当作 cpu 空闲的另一种形式,它额外给出了 cpu 空闲的线索。
i/o 处理同样会消耗系统时间。一个高于20%的平均系统时间,往往值得进一步发掘:也许系统花在 i/o 的时间太长了。
在上面的例子中,cpu 基本把时间花在用户态里面,意味着跑在上面的应用占用了大部分时间。此外,cpu 平均使用率在90%之上。这不一定是个问题;检查下“r”列,看看是否饱和了。
<code>$ mpstat -p all 1</code>
<code>linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 cpu)</code>
<code></code>
<code>07:38:49 pm cpu %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle</code>
<code>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</code>
<code>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</code>
<code>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</code>
<code>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</code>
<code>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</code>
这个命令显示每个 cpu 的时间使用百分比,你可以用它来检查 cpu 是否存在负载不均衡。单个过于忙碌的 cpu 可能意味着整个应用只有单个线程在工作。
<code>$ pidstat 1</code>
<code>linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 cpu)</code>
<code>07:41:02 pm uid pid %usr %system %guest %cpu cpu command</code>
<code>07:41:03 pm 0 9 0.00 0.94 0.00 0.94 1 rcuos/0</code>
<code>07:41:03 pm 0 4214 5.66 5.66 0.00 11.32 15 mesos-slave</code>
<code>07:41:03 pm 0 4354 0.94 0.94 0.00 1.89 8 java</code>
<code>07:41:03 pm 0 6521 1596.23 1.89 0.00 1598.11 27 java</code>
<code>07:41:03 pm 0 6564 1571.70 7.55 0.00 1579.25 28 java</code>
<code>07:41:03 pm 60004 60154 0.94 4.72 0.00 5.66 9 pidstat</code>
<code>07:41:03 pm uid pid %usr %system %guest %cpu cpu command</code>
<code>07:41:04 pm 0 4214 6.00 2.00 0.00 8.00 15 mesos-slave</code>
<code>07:41:04 pm 0 6521 1590.00 1.00 0.00 1591.00 27 java</code>
<code>07:41:04 pm 0 6564 1573.00 10.00 0.00 1583.00 28 java</code>
<code>07:41:04 pm 108 6718 1.00 0.00 0.00 1.00 0 snmp-pass</code>
<code>07:41:04 pm 60004 60154 1.00 4.00 0.00 5.00 9 pidstat</code>
<code>pidstat</code>看上去就像<code>top</code>,不过<code>top</code>的输出会覆盖掉之前的输出,而<code>pidstat</code>的输出则添加在之前的输出的后面。这有利于观察数据随时间的变动情况,也便于把你看到的内容复制粘贴到调查报告中。
上面的例子表明,cpu 主要消耗在两个 java 进程上。<code>%cpu</code>列是在各个 cpu 上的使用量的总和;<code>1591%</code>意味着 java 进程消耗了将近16个 cpu。
<code>$ iostat -xz 1</code>
<code>avg-cpu: %user %nice %system %iowait %steal %idle</code>
<code>73.96 0.00 3.73 0.03 0.06 22.21</code>
<code>device: rrqm/s wrqm/s r/s w/s rkb/s wkb/s avgrq-sz avgqu-sz await r_await w_await svctm %util</code>
<code>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</code>
<code>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</code>
<code>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</code>
<code>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</code>
<code>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</code>
<code>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</code>
这个命令可以弄清块设备(磁盘)的状况,包括工作负载和处理性能。注意以下各项:
r/s,w/s,rkb/s,wkb/s:分别表示每秒设备读次数,写次数,读的 kb 数,写的 kb 数。它们描述了磁盘的工作负载。也许性能问题就是由过高的负载所造成的。
await:i/o 平均时间,以毫秒作单位。它是应用中 i/o 处理所实际消耗的时间,因为其中既包括排队用时也包括处理用时。如果它比预期的大,就意味着设备饱和了,或者设备出了问题。
avgqu-sz:分配给设备的平均请求数。大于1表示设备已经饱和了。(不过有些设备可以并行处理请求,比如由多个磁盘组成的虚拟设备)
%util:设备使用率。这个值显示了设备每秒内工作时间的百分比,一般都处于高位。低于60%通常是低性能的表现(也可以从 await 中看出),不过这个得看设备的类型。接近100%通常意味着饱和。
如果某个存储设备是由多个物理磁盘组成的逻辑磁盘设备,100%的使用率可能只是意味着 i/o 占用。
请牢记于心,磁盘 i/o 性能低不一定是个问题。应用的 i/o 往往是异步的(比如预读read-ahead和写缓冲buffering for writes),所以不一定会被阻塞并遭受延迟。
<code>$ free -m</code>
<code>total used free shared buffers cached</code>
<code>mem: 245998 24545 221453 83 59 541</code>
<code>-/+ buffers/cache: 23944 222053</code>
<code>swap: 0 0 0</code>
右边的两列显示:
buffers:用于块设备 i/o 的缓冲区缓存
cached:用于文件系统的页缓存
它们的值接近于0时,往往导致较高的磁盘 i/o(可以通过 <code>iostat</code> 确认)和糟糕的性能。上面的例子里没有这个问题,每一列都有好几 m 呢。
如果你在 linux 上安装了 zfs,正如我们在一些服务上所做的,这一点会变得更加迷惑,因为 zfs 它自己的文件系统缓存不算入<code>free -m</code>。有时系统看上去已经没有多少空闲内存可用了,其实内存都待在 zfs 的缓存里呢。
<code>$ sar -n dev 1</code>
<code>linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 cpu)</code>
<code>12:16:48 am iface rxpck/s txpck/s rxkb/s txkb/s rxcmp/s txcmp/s rxmcst/s %ifutil</code>
<code>12:16:49 am eth0 18763.00 5032.00 20686.42 478.30 0.00 0.00 0.00 0.00</code>
<code>12:16:49 am lo 14.00 14.00 1.36 1.36 0.00 0.00 0.00 0.00</code>
<code>12:16:49 am docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00</code>
<code>12:16:49 am iface rxpck/s txpck/s rxkb/s txkb/s rxcmp/s txcmp/s rxmcst/s %ifutil</code>
<code>12:16:50 am eth0 19763.00 5101.00 21999.10 482.56 0.00 0.00 0.00 0.00</code>
<code>12:16:50 am lo 20.00 20.00 3.25 3.25 0.00 0.00 0.00 0.00</code>
<code>12:16:50 am docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00</code>
这个命令可以用于检查网络流量的工作负载:rxkb/s 和 txkb/s,以及它是否达到限额了。上面的例子中,<code>eth0</code>接收的流量达到 22mbytes/s,也即 176mbits/sec(限额是 1gbit/sec)
<code>$ sar -n tcp,etcp 1</code>
<code>12:17:19 am active/s passive/s iseg/s oseg/s</code>
<code>12:17:20 am 1.00 0.00 10233.00 18846.00</code>
<code>12:17:19 am atmptf/s estres/s retrans/s isegerr/s orsts/s</code>
<code>12:17:20 am 0.00 0.00 0.00 0.00 0.00</code>
<code>12:17:20 am active/s passive/s iseg/s oseg/s</code>
<code>12:17:21 am 1.00 0.00 8359.00 6039.00</code>
<code>12:17:20 am atmptf/s estres/s retrans/s isegerr/s orsts/s</code>
<code>12:17:21 am 0.00 0.00 0.00 0.00 0.00</code>
这个命令显示一些关键tcp指标的汇总。其中包括:
active/s:本地每秒创建的 tcp 连接数(比如 concept() 创建的)
passive/s:远程每秒创建的 tcp 连接数(比如 accept() 创建的)
retrans/s:每秒 tcp 重传次数
主动连接数active和被动连接数passive通常可以用来粗略地描述系统负载。可以认为主动连接是对外的,而被动连接是对内的,虽然严格来说不完全是这个样子。(比如,一个从 localhost 到 localhost 的连接)
重传是网络或系统问题的一个信号;它可能是不可靠的网络(比如公网)所造成的,也有可能是服务器已经过载并开始丢包。在上面的例子中,每秒只创建一个新的 tcp 连接。
<code>$ top</code>
<code>top - 00:15:40 up 21:56, 1 user, load average: 31.09, 29.87, 29.92</code>
<code>tasks: 871 total, 1 running, 868 sleeping, 0 stopped, 2 zombie</code>
<code>%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</code>
<code>kib mem: 25190241+total, 24921688 used, 22698073+free, 60448 buffers</code>
<code>kib swap: 0 total, 0 used, 0 free. 554208 cached mem</code>
<code>pid user pr ni virt res shr s %cpu %mem time+ command</code>
<code>20248 root 20 0 0.227t 0.012t 18748 s 3090 5.2 29812:58 java</code>
<code>4213 root 20 0 2722544 64640 44232 s 23.5 0.0 233:35.37 mesos-slave</code>
<code>66128 titancl+ 20 0 24344 2332 1172 r 1.0 0.0 0:00.07 top</code>
<code>5235 root 20 0 38.227g 547004 49996 s 0.7 0.2 2:02.74 java</code>
<code>4299 root 20 0 20.015g 2.682g 16836 s 0.3 1.1 33:14.42 java</code>
<code>1 root 20 0 33620 2920 1496 s 0.0 0.0 0:03.82 init</code>
<code>2 root 20 0 0 0 0 s 0.0 0.0 0:00.02 kthreadd</code>
<code>3 root 20 0 0 0 0 s 0.0 0.0 0:05.35 ksoftirqd/0</code>
<code>5 root 0 -20 0 0 0 s 0.0 0.0 0:00.00 kworker/0:0h</code>
<code>6 root 20 0 0 0 0 s 0.0 0.0 0:06.94 kworker/u256:0</code>
<code>8 root 20 0 0 0 0 s 0.0 0.0 2:38.05 rcu_sched</code>
<code>top</code>命令包括很多我们之前检查过的指标。它适合用来查看相比于之前的命令输出的结果,负载有了哪些变动。
不能清晰显示数据随时间变动的情况,这是<code>top</code>的一个缺点。相较而言,<code>vmstat</code>和<code>pidstat</code>的输出不会覆盖掉之前的结果,因此更适合查看数据随时间的变动情况。另外,如果你不能及时暂停<code>top</code>的输出(<code>ctrl-s</code> 暂停,<code>ctrl-q</code> 继续),也许某些关键线索会湮灭在新的输出中。
本文来自云栖社区合作伙伴“linux中国”
原文发布时间为:2013-04-02.