链接:https://zhuanlan.zhihu.com/p/180402964
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
系统平均负载:是处于可运行或不可中断状态的平均进程数。
可运行进程:使用 CPU 或等待使用 CPU 的进程
不可中断状态进程:正在等待某些 IO 访问,一般是和硬件交互,不可被打断(不可被打断的原因是为了保护系统数据一致,防止数据读取错误)
首先top
命令查看进程运行状态,如下:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10760 user 20 0 3061604 84832 5956 S 82.4 0.6 126:47.61 Process
29424 user 20 0 54060 2668 1360 R 17.6 0.0 0:00.03 **top**
程序状态Status
进程可运行状态为R
,不可中断运行为D
(后续讲解 top 时会详细说明)
top查看系统平均负载:
top - 13:09:42 up 888 days, 21:32, 8 users, load average: 19.95, 14.71, 14.01
Tasks: 642 total, 2 running, 640 sleeping, 0 stopped, 0 zombie
%Cpu0 : 37.5 us, 27.6 sy, 0.0 ni, 30.9 id, 0.0 wa, 0.0 hi, 3.6 si, 0.3 st
%Cpu1 : 34.1 us, 31.5 sy, 0.0 ni, 34.1 id, 0.0 wa, 0.0 hi, 0.4 si, 0.0 st
...
KiB Mem : 14108016 total, 2919496 free, 6220236 used, 4968284 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 6654506 avail Mem
这里的load average
就表示系统最近 1 分钟、5 分钟、15 分钟的系统瓶颈负载。
uptime查看系统瓶颈负载
[root /home/user]# uptime
13:11:01 up 888 days, 21:33, 8 users, load average: 17.20, 14.85, 14.10
系统平均负载和 CPU 核数密切相关,我们可以通过以下命令查看当前机器 CPU 信息:
lscpu查看 CPU 信息:
[root@Tencent-SNG /home/user_00]# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
...
L1d cache: 32K
L1i cache: 32K
L2 cache: 4096K
NUMA node0 CPU(s): 0-7 // NUMA架构信息
cat /proc/cpuinfo查看每个 CPU 核的信息:
processor : 7 // 核编号7
vendor_id : GenuineIntel
cpu family : 6
model : 6
...
一般来说,系统平均负载升高意味着 CPU 使用率上升。但是他们没有必然联系,CPU 密集型计算任务较多一般系统平均负载会上升,但是如果 IO 密集型任务较多也会导致系统平均负载升高但是此时的 CPU 使用率不一定高,可能很低因为很多进程都处于不可中断状态,等待 CPU 调度也会升高系统平均负载。
所以假如我们系统平均负载很高,但是 CPU 使用率不是很高,则需要考虑是否系统遇到了 IO 瓶颈,应该优化 IO 读写速度。
所以系统是否遇到 CPU 瓶颈需要结合 CPU 使用率,系统瓶颈负载一起查看(当然还有其他指标需要对比查看,下面继续讲解)
stress
是一个施加系统压力和压力测试系统的工具,我们可以使用stress
工具压测试 CPU,以便方便我们定位和排查 CPU 问题。
yum install stress // 安装stress工具
// --cpu 8:8个进程不停的执行sqrt()计算操作
// --io 4:4个进程不同的执行sync()io操作(刷盘)
// --vm 2:2个进程不停的执行malloc()内存申请操作
// --vm-bytes 128M:限制1个执行malloc的进程申请内存大小
stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s
我们这里主要验证 CPU、IO、进程数过多的问题
使用stress -c 1
模拟 CPU 高负载情况,然后使用如下命令观察负载变化情况:
uptime:使用uptime
查看此时系统负载:
# -d 参数表示高亮显示变化的区域
$ watch -d uptime
... load average: 1.00, 0.75, 0.39
mpstat:使用mpstat -P ALL 1
则可以查看每一秒的 CPU 每一核变化信息,整体和top
类似,好处是可以把每一秒(自定义)的数据输出方便观察数据的变化,最终输出平均数据:
13:14:53 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
13:14:58 all 12.89 0.00 0.18 0.00 0.00 0.03 0.00 0.00 0.00 86.91
13:14:58 0 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
13:14:58 1 0.40 0.00 0.20 0.00 0.00 0.20 0.00 0.00 0.00 99.20
由以上输出可以得出结论,当前系统负载升高,并且其中 1 个核跑满主要在执行用户态任务,此时大多数属于业务工作。所以此时需要查哪个进程导致单核 CPU 跑满:
pidstat:使用pidstat -u 1
则是每隔 1 秒输出当前系统进程、CPU 数据:
13:18:00 UID PID %usr %system %guest %CPU CPU Command
13:18:01 0 1 1.00 0.00 0.00 1.00 4 systemd
13:18:01 0 3150617 100.00 0.00 0.00 100.00 0 stress
...
top:当然最方便的还是使用top
命令查看负载情况:
top - 13:19:06 up 125 days, 20:01, 3 users, load average: 0.99, 0.63, 0.42
Tasks: 223 total, 2 running, 221 sleeping, 0 stopped, 0 zombie
%Cpu(s): 14.5 us, 0.3 sy, 0.0 ni, 85.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16166056 total, 3118532 free, 9550108 used, 3497416 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 6447640 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3150617 root 20 0 10384 120 0 R 100.0 0.0 4:36.89 stress
此时可以看到是stress
占用了很高的 CPU。
我们使用stress -i 1
来模拟 IO 瓶颈问题,即死循环执行 sync 刷盘操作: uptime:使用uptime
查看此时系统负载:
$ watch -d uptime
..., load average: 1.06, 0.58, 0.37
mpstat:查看此时 IO 消耗,但是实际上我们发现这里 CPU 基本都消耗在了 sys 即系统消耗上。
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.33 0.00 12.64 0.13 0.00 0.00 0.00 0.00 0.00 86.90
Average: 0 0.00 0.00 99.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: 1 0.00 0.00 0.33 0.00 0.00 0.00 0.00 0.00 0.00 99.67
IO 无法升高的问题:
iowait 无法升高的问题,是因为案例中 stress 使用的是 sync()
系统调用,它的作用是刷新缓冲区内存到磁盘中。对于新安装的虚拟机,缓冲区可能比较小,无法产生大的 IO 压力,这样大部分就都是系统调用的消耗了。所以,你会看到只有系统 CPU 使用率升高。解决方法是使用 stress 的下一代 stress-ng,它支持更丰富的选项,比如stress-ng -i 1 --hdd 1 --timeout 600
(–hdd 表示读写临时文件)。
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.25 0.00 0.44 26.22 0.00 0.00 0.00 0.00 0.00 73.09
Average: 0 0.00 0.00 1.02 98.98 0.00 0.00 0.00 0.00 0.00 0.00
pidstat:同上(略)
可以看出 CPU 的 IO 升高导致系统平均负载升高。我们使用pidstat
查找具体是哪个进程导致 IO 升高的。
top:这里使用 top 依旧是最方面的查看综合参数,可以得出stress
是导致 IO 升高的元凶。
pidstat 没有 iowait 选项:可能是 CentOS 默认的sysstat
太老导致,需要升级到 11.5.5 之后的版本才可用。
进程数过多这个问题比较特殊,如果系统运行了很多进程超出了 CPU 运行能,就会出现等待 CPU 的进程。 使用stress -c 24
来模拟执行 24 个进程(我的 CPU 是 8 核) uptime:使用uptime
查看此时系统负载:
$ watch -d uptime
..., load average: 18.50, 7.13, 2.84
mpstat:同上(略)
pidstat:同上(略)
可以观察到此时的系统处理严重过载的状态,平均负载高达 18.50。
top:我们还可以使用top
命令查看此时Running
状态的进程数,这个数量很多就表示系统正在运行、等待运行的进程过多。
通过以上问题现象及解决思路可以总结出:
总结工具:mpstat
、pidstat
、top
和uptime
CPU 上下文:CPU 执行每个任务都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好 CPU 寄存器和程序计数器(Program Counter,PC)包括 CPU 寄存器在内都被称为 CPU 上下文。
CPU 上下文切换:CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
CPU 上下文切换:分为进程上下文切换、线程上下文切换以及中断上下文切换。
从用户态切换到内核态需要通过系统调用来完成,这里就会发生进程上下文切换(特权模式切换),当切换回用户态同样发生上下文切换。
一般每次上下文切换都需要几十纳秒到数微秒的 CPU 时间,如果切换较多还是很容易导致 CPU 时间的浪费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,这里同样会导致系统平均负载升高。
Linux 为每个 CPU 维护一个就绪队列,将 R 状态进程按照优先级和等待 CPU 时间排序,选择最需要的 CPU 进程执行。这里运行进程就涉及了进程上下文切换的时机:
sleep
。线程和进程:
所以线程上下文切换包括了 2 种情况:
中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。
对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。
vmstat:工具可以查看系统的内存、CPU 上下文切换以及中断次数:
// 每隔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
3 0 0 157256 3241604 5144444 0 0 20 0 26503 33960 18 7 75 0 0
17 0 0 159984 3241708 5144452 0 0 12 0 29560 37696 15 10 75 0 0
6 0 0 162044 3241816 5144456 0 0 8 120 30683 38861 17 10 73 0 0
cs:则为每秒的上下文切换次数。
in:则为每秒的中断次数。
r:就绪队列长度,正在运行或等待 CPU 的进程。
b:不可中断睡眠状态的进程数,例如正在和硬件交互。
pidstat:使用pidstat -w
选项查看具体进程的上下文切换次数:
$ pidstat -w -p 3217281 1
10:19:13 UID PID cswch/s nvcswch/s Command
10:19:14 0 3217281 0.00 18.00 stress
10:19:15 0 3217281 0.00 18.00 stress
10:19:16 0 3217281 0.00 28.71 stress
其中cswch/s
和nvcswch/s
表示自愿上下文切换和非自愿上下文切换。
自愿上下文切换:是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。
非自愿上下文切换:则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换
这里我们使用sysbench
工具模拟上下文切换问题。
先使用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
2 0 0 514540 3364828 5323356 0 0 10 16 0 0 4 1 95 0 0
1 0 0 514316 3364932 5323408 0 0 8 0 27900 34809 17 10 73 0 0
1 0 0 507036 3365008 5323500 0 0 8 0 23750 30058 19 9 72 0 0
然后使用sysbench --threads=64 --max-time=300 threads run
模拟 64 个线程执行任务,此时我们再次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
2 0 0 318792 3385728 5474272 0 0 10 16 0 0 4 1 95 0 0
1 0 0 307492 3385756 5474316 0 0 8 0 15710 20569 20 8 72 0 0
1 0 0 330032 3385824 5474376 0 0 8 16 21573 26844 19 9 72 0 0
2 0 0 321264 3385876 5474396 0 0 12 0 21218 26100 20 7 73 0 0
6 0 0 320172 3385932 5474440 0 0 12 0 19363 23969 19 8 73 0 0
14 0 0 323488 3385980 5474828 0 0 64 788 111647 3745536 24 61 15 0 0
14 0 0 323576 3386028 5474856 0 0 8 0 118383 4317546 25 64 11 0 0
16 0 0 315560 3386100 5475056 0 0 8 16 115253 4553099 22 68 9 0 0
我们可以明显的观察到:
我们使用pidstat
查看当前 CPU 信息和具体的进程上下文切换信息:
// -w表示查看进程切换信息,-u查看CPU信息,-t查看线程切换信息
$ pidstat -w -u -t 1
10:35:01 UID PID %usr %system %guest %CPU CPU Command
10:35:02 0 3383478 67.33 100.00 0.00 100.00 1 sysbench
10:35:01 UID PID cswch/s nvcswch/s Command
10:45:39 0 3509357 - 1.00 0.00 kworker/2:2
10:45:39 0 - 3509357 1.00 0.00 |__kworker/2:2
10:45:39 0 - 3509702 38478.00 45587.00 |__sysbench
10:45:39 0 - 3509703 39913.00 41565.00 |__sysbench
所以我们可以看到大量的sysbench
线程存在很多的上下文切换。
我们可以查看系统的watch -d cat /proc/softirqs
以及watch -d cat /proc/interrupts
来查看系统的软中断和硬中断(内核中断)。我们这里主要观察/proc/interrupts
即可。
$ watch -d cat /proc/interrupts
RES: 900997016 912023527 904378994 902594579 899800739 897500263 895024925 895452133 Rescheduling interrupts
这里明显看出重调度中断(RES)增多,这个中断表示唤醒空闲状态 CPU 来调度新任务执行,
/proc/interrupts
文件来分析具体的中断类型。除了系统负载、上下文切换信息,最直观的 CPU 问题指标就是 CPU 使用率信息。Linux 通过/proc
虚拟文件系统向用户控件提供系统内部状态信息,其中/proc/stat
则是 CPU 和任务信息统计。
$ cat /proc/stat | grep cpu
cpu 6392076667 1160 3371352191 52468445328 3266914 37086 36028236 20721765 0 0
cpu0 889532957 175 493755012 6424323330 2180394 37079 17095455 3852990 0 0
...
这里每一列的含义如下:
这里我们可以使用top
、ps
、pidstat
等工具方便的查询这些数据,可以很方便的看到 CPU 使用率很高的进程,这里我们可以通过这些工具初步定为,但是具体的问题原因还需要其他方法继续查找。
这里我们可以使用perf top
方便查看热点数据,也可以使用perf record
可以将当前数据保存起来方便后续使用perf report
查看。
这里总结一下 CPU 使用率问题及排查思路:
CPU 使用率主要包含以下几个方面:
反应了系统的整体负载情况,可以查看过去 1 分钟、过去 5 分钟和过去 15 分钟的平均负载。
上下文切换主要关注 2 项指标:
CPU 的访问速度远大于内存访问,这样在 CPU 访问内存时不可避免的要等待内存响应。为了协调 2 者的速度差距出现了 CPU 缓存(多级缓存)。 如果 CPU 缓存命中率越高则性能会更好,我们可以使用以下工具查看 CPU 缓存命中率,工具地址、项目地址 perf-tools
# ./cachestat -t
Counting cache functions... Output every 1 seconds.
TIME HITS MISSES DIRTIES RATIO BUFFERS_MB CACHE_MB
08:28:57 415 0 0 100.0% 1 191
08:28:58 411 0 0 100.0% 1 191
08:28:59 362 97 0 78.9% 0 8
08:29:00 411 0 0 100.0% 0 9
08:29:01 775 20489 0 3.6% 0 89
08:29:02 411 0 0 100.0% 0 89
08:29:03 6069 0 0 100.0% 0 89
08:29:04 15249 0 0 100.0% 0 89
08:29:05 411 0 0 100.0% 0 89
08:29:06 411 0 0 100.0% 0 89
08:29:07 411 0 3 100.0% 0 89
[...]
性能指标工具说明平均负载uptime
topuptime 简单展示最近一段时间的平均负载
top 展示更多指标CPU 使用率vmstat
mpstat
top
sar
/proc/stat
top、vmstat、mpstat 只可以动态查看当前,而 sar 可以查看历史
/proc/stat 是其他性能工具的数据来源进程 CPU 使用率top
pidstat
ps
htop
atop
top、ps 可以以排序方式展示进程 CPU、pidstat 不可排序展示
htop、atop 则以不同颜色展示各类数据更直观系统上下文切换vmstat展示上下文切换此时、运行状态、不可中断状态进程数量进程上下文切换pidstat展示项很多,包括进程上下文切换信息软中断top
/proc/softirqs
mpstattop 可查看软中断 CPU 使用率
/proc/softirqs 和 mpstat 则可以查看每个 CPU 上的累计信息硬中断vmstat
/proc/interruptsvmstat 查看总中断次数信息
/proc/interrupts 查看各种中断在每个 CPU 核心上的累计信息网络dstat
sar
tcpdumpdstat、sar 较详细的展示出总的网络收发情况
tcpdump 提供动态抓取数据包的能力IOdstat、sar2 者都提供了详细的 IO 整体情况CPU 信息/proc/cpuinfo
lscpu都可以查看 CPU 信息系统分析perf
execsnoopperf 分析各种内核函数调用、热点函数信息
execsnoop 监控短时进程
性能工具CPU 性能指标uptime5、10、15 分钟内的平均负载展示top平均负载、运行队列、CPU 各项使用率、进程状态和 CPU 使用率htoptop 增强版,以不同颜色区分不同类型进程,展示更直观atopCPU、内存、磁盘、网络资源全访问监控,十分齐全vmstat系统整体 CPU 使用率、上下文切换次数、中断次数,还包括处于运行(r)和不可中断状态(b)的进程数量pidstat进程、线程(-t)的每个 CPU 占用信息,中断上下文切换次数/proc/softirqs展示每个 CPU 上的软中断类型及次数/proc/inerrupts展示每个 CPU 上的硬中断类型及次数ps每个进程的状态和 CPU 使用率pstree进程的父子关系展示dstat系统整体 CPU 使用率(以及相关 IO、网络信息)sar系统整体 CPU 使用率,以及使用率历史信息strace跟踪进程的系统调用perfCPU 性能事件分析,例如:函数调用链、CPU 缓存命中率、CPU 调度等execsnoop短时进程分析
有了以上性能工具,在实际遇到问题时我们并不可能全部性能工具跑一遍,这样效率也太低了,所以这里可以先运行几个常用的工具 top、vmstat、pidstat 分析系统大概的运行情况然后在具体定位原因。
top 系统CPU => vmstat 上下文切换次数 => pidstat 非自愿上下文切换次数 => 各类进程分析工具(perf strace ps execsnoop pstack)
top 用户CPU => pidstat 用户CPU => 一般是CPU计算型任务
top 僵尸进程 => 各类进程分析工具(perf strace ps execsnoop pstack)
top 平均负载 => vmstat 运行状态进程数 => pidstat 用户CPU => 各类进程分析工具(perf strace ps execsnoop pstack)
top 等待IO CPU => vmstat 不可中断状态进程数 => IO分析工具(dstat、sar -d)
top 硬中断 => vmstat 中断次数 => 查看具体中断类型(/proc/interrupts)
top 软中断 => 查看具体中断类型(/proc/softirqs) => 网络分析工具(sar -n、tcpdump) 或者 SCHED(pidstat 非自愿上下文切换)
性能优化往往是多方面的,CPU、内存、网络等都是有关联的,这里暂且给出 CPU 优化的思路,以供参考。
gcc -O2
对程序代码优化。nlogn
的排序算法,使用logn
的查找算法等。作者:Wayne
链接:https://zhuanlan.zhihu.com/p/185033376
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
当你发现 Linux 服务器上的系统性能问题,在最开始的 1 分钟时间里,你会查看哪些系统指标呢?
Netflix 在 AWS 上有着大规模的 EC2 集群,以及各种各样的性能分析和监控工具。比如我们使用 Atlas 来监控整个平台,用 Vector 实时分析 EC2 实例的性能。这些工具已经能够帮助我们解决大部分的问题,但是有时候我们还是要登录进机器内部,用一些标准的 Linux 性能分析工具来定位问题。
在这篇文章里,Netflix 性能工程团队会介绍一些我们使用的标准的 Linux 命令行工具,在发现问题的前 60 秒内去分析和定位问题。在这 60 秒内,你可以使用下面这 10 个命令行了解系统整体的运行情况,以及当前运行的进程对资源的使用情况。在这些指标里面,我们先关注和错误、以及和资源饱和率相关的指标,然后再看资源使用率。相对来讲,错误和资源饱和率比较容易理解。饱和的意思是指一个资源(CPU,内存,磁盘)上的负载超过了它能够处理的能力,这时候我们观察到的现象就是请求队列开始堆积,或者请求等待的时间变长。
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)、资源饱和度(Satuation)、错误(Error),这三个方面对所有的资源进行分析(CPU,内存,磁盘等等)。在这个分析的过程中,我们也要时刻注意我们已经排除过的资源问题,以便缩小我们定位的范围,给下一步的定位提供更明确的方向。
下面的章节对每个命令行做了一个说明,并且使用了我们在生产环境的数据作为例子。对这些命令行更详细的描述,请查看相应的帮助文档。
$ uptime
23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02
这个命令能很快地检查系统平均负载,你可以认为这个负载的值显示的是有多少任务在等待运行。在 Linux 系统里,这包含了想要或者正在使用 CPU 的任务,以及在 io 上被阻塞的任务。这个命令能使我们对系统的全局状态有一个大致的了解,但是我们依然需要使用其它工具获取更多的信息。
这三个值是系统计算的 1 分钟、5 分钟、15 分钟的指数加权的动态平均值,可以简单地认为就是这个时间段内的平均值。根据这三个值,我们可以了解系统负载随时间的变化。比如,假设现在系统出了问题,你去查看这三个值,发现 1 分钟的负载值比 15 分钟的负载值要小很多,那么你很有可能已经错过了系统出问题的时间点。
在上面这个例子里面,负载的平均值显示 1 分钟为 30,比 15 分钟的 19 相比增长较多。有很多原因会导致负载的增加,也许是 CPU 不够用了;vmstat 或者 mpstat 可以进一步确认问题在哪里。
$ 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 count
这个命令显示了最新的几条系统日志。这里我们主要找一下有没有一些系统错误会导致性能的问题。上面的例子包含了 oom-killer 以及 TCP 丢包。
不要略过这一步!dmesg 永远值得看一看。
$ 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 展示了虚拟内存、CPU 的一些情况。上面这个例子里命令行的 1 表示每隔 1 秒钟显示一次。在这个版本的 vmstat 里,第一行表示了这一次启动以来的各项指标,我们可以暂时忽略掉第一行。
需要查看的指标:
把用户态 CPU 时间(us)和内核态 CPU 时间(sy)加起来,我们可以进一步确认 CPU 是否繁忙。等待 IO 的时间 (wa)高的话,表示磁盘是瓶颈;注意,这个也被包含在空闲时间里面(id), CPU 这个时候也是空闲的,任务此时阻塞在磁盘 IO 上了。你可以把等待 IO 的时间(wa)看做另一种形式的 CPU 空闲,它可以告诉你 CPU 为什么是空闲的。
系统处理 IO 的时候,肯定是会消耗内核态时间(sy)的。如果内核态时间较多的话,比如超过 20%,我们需要进一步分析,也许内核对 IO 的处理效率不高。
在上面这个例子里,CPU 时间大部分都消耗在了用户态,表明主要是应用层的代码在使用 CPU。CPU 利用率 (us + sy)也超过了 90%,这不一定是一个问题;我们可以通过 r 和 CPU 个数确定 CPU 的饱和度。
$ 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
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 那样每次都清屏。这个命令可以方便地查看进程可能存在的行为模式,你也可以直接 copy past,可以方便地记录随着时间的变化,各个进程运行状况的变化。
上面的例子说明有 2 个 Java 进程消耗了大量 CPU。这里的 %CPU 表明的是对所有 CPU 的值,比如 1591% 标识这个 Java 进程几乎消耗了 16 个 CPU。
$ 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
iostat 是理解块设备(磁盘)的当前负载和性能的重要工具。几个指标的含义:
如果这个块设备是一个逻辑块设备,这个逻辑快设备后面有很多物理的磁盘的话,100% 利用率只能表明有些 IO 的处理时间达到了 100%;后端的物理磁盘可能远远没有达到饱和状态,可以处理更多的负载。
还有一点需要注意的是,较差的磁盘 IO 性能并不一定意味着应用程序会有问题。应用程序可以有许多方法执行异步 IO,而不会阻塞在 IO 上面;应用程序也可以使用诸如预读取,写缓冲等技术降低 IO 延迟对自身的影响。
$ free -m
total used free shared buffers cached
Mem: 245998 24545 221453 83 59 541
-/+ buffers/cache: 23944 222053
Swap:
右边的两列显式:
我们只是想要检查这些不接近零的大小,其可能会导致更高磁盘 I/O(使用 iostat 确认),和更糟糕的性能。上面的例子看起来还不错,每一列均有很多 M 个大小。
比起第一行,-/+ buffers/cache 提供的内存使用量会更加准确些。Linux 会把暂时用不上的内存用作缓存,一旦应用需要的时候就立刻重新分配给它。所以部分被用作缓存的内存其实也算是空闲的内存。为了解释这一点, 甚至有人专门建了个网站: http://www.linuxatemyram.com/。
如果使用 ZFS 的话,可能会有点困惑。ZFS 有自己的文件系统缓存,在 free -m 里面看不到;系统看起来空闲内存不多了,但是有可能 ZFS 有很多的缓存可用。
$ 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 Mbytes/s,差不多 176 Mbits/sec ,比 1 Gbit/sec 还要少很多。
这个例子里也有 %ifutil 标识设备利用率,我们也用 Brenan 的 nicstat tool 测量。和 nicstat 一样,这个设备利用率很难测量正确,上面的例子里好像这个值还有点问题。
$ 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 重要指标的一些概括,包括:
重传表示网络或者服务器的问题。也许是网络不稳定了,也许是服务器负载过重开始丢包了。上面这个例子表示每秒只有 1 个新连接建立。
$ 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 继续),一些间歇性问题的线索也可能由于被清屏而丢失。