作者 | 勿非
本文以系统为中心, 结合日常工作和用例, 由浅入深地介绍了性能分析的一些方法和体会, 希望对想了解系统性能分析的同学有所帮助。
入门篇
资源角度
USE
产品跑在系统的各种资源上面, 从系统资源的角度入门性能分析是个不错的选择, 我们以业界知名大牛 Brendan Gregg 的 USE 方法开始, USE 特点就是简单有效适合入门, 用 Brendan 的话描述 USE 的效果:
I find it solves about 80% of server issues with 5% of the effort.
USE 从系统资源的角度, 包括但不限于 CPU, 内存, 磁盘, 网络等, 关注以下3个方面:
• Utilization (U): as a percent over a time interval. eg, "one disk is running at 90% utilization". 大多数情况可以合理推测利用率高可能会影响性能
• Saturation (S): as a queue length. eg, "the CPUs have an average run queue length of four". 资源竞争的激烈程度
• Errors (E). scalar counts. eg, "this network interface has had fifty late collisions". Errors 相对直观
CPU
对于 CPU, 主要关注以下指标: • Utilization. CPU 的利用率 • Saturation. 可以是 load average, runqueue length, sched latency 等
CPU 利用率用 top 看下:
top - 17:13:49 up 83 days, 23:10, 1 user, load average: 433.52, 422.54, 438.70
Tasks: 2765 total, 23 running, 1621 sleeping, 0 stopped, 34 zombie
%Cpu(s): 23.4 us, 9.5 sy, 0.0 ni, 65.5 id, 0.7 wa, 0.0 hi, 1.0 si, 0.0 st
CPU 利用率拆分成了更细粒度的几部分: • us, sys, ni - 对应 un-niced user, kernel, niced user 的 CPU 利用率 • id, wa - 对应到 idle, io wait 的比例, io wait 本质上也是一种 idle, 区别在于对应 cpu 上有等待 io 的任务 • hi, si - 对应 hardirq, softirq 的比例 • st - 因为超卖等原因, hypervisor 从该 vm 偷走的时间 (todo: docker)
继续看 load average, 3 个数值分别对应到系统 1/5/15 分钟内的系统平均 load, load 是个比较模糊的概念, 可以简单认为是对资源有需求的任务数, 包括 on cpu, runnable 的任务, 也包括等待 IO 及任意 D 状态的任务. load 使用采样的方式, 每隔 5 秒采样一样, 越近的采样权重越大, 这样从 1/5/15 的趋势可以看出系统压力的变化。
load average: 433.52, 422.54, 438.70
在这台 128 个 CPU 的机器上, loadavg 看起来有些偏高, 但是具体影响目前不得而知, 性能低是相对具体目标而言的, load 高只是现象, 它可能相关也可能无关, 但至少是值得注意的。
再看下 dstat 关于任务状态的统计: • run - 对应到/proc/stat 里面的 procs_running, 也就是 runnable 任务数 • blk - 对应到/proc/stat 里面的 procs_blocked, 阻塞在 I/O 的任务数
实际上和 loadavg 没有本质区别, 只是 load 模糊了 runnable 和 D 状态, 同时 load 使用 1/5/15 分钟的力度, 而 dstat 可以使用更细粒度, 如果只看某一时间点用 load, 如果要观察长时间的变化使用 dstat (/proc/stat)。
#dstat -tp
----system---- ---procs---
time |run blk new
07-03 17:56:50|204 1.0 202
07-03 17:56:51|212 0 238
07-03 17:56:52|346 1.0 266
07-03 17:56:53|279 5.0 262
07-03 17:56:54|435 7.0 177
07-03 17:56:55|442 3.0 251
07-03 17:56:56|792 8.0 419
07-03 17:56:57|504 16 152
07-03 17:56:58|547 3.0 156
07-03 17:56:59|606 2.0 212
07-03 17:57:00|770 0 186
内存
这里主要关注内存容量方面, 不关注访存的性能。 • Utilization. 内存利用率 • Saturation. 这里主要考察内存回收算法的效率
简单的内存利用率用 free 命令: • total - MemTotal + SwapTotal, 一般来说 MemTotal 会略小于真实的物理内存 • free - 未使用的内存. Linux 倾向于缓存更多页面以提高性能, 所以不能简单通过 free 来判断内存是否不足 • buff/cache - 系统缓存, 一般不需要严格区分 buffer 和 cache • available - 估计的可用物理内存大小 • used - 等于 total - free - buffers - cache • Swap - 该机器上未配置
#free -g
total used free shared buff/cache available
Mem: 503 193 7 2 301 301
Swap: 0 0 0
更详细的信息可以直接去读/proc/meminfo:
#cat /proc/meminfo
MemTotal: 527624224 kB
MemFree: 8177852 kB
MemAvailable: 316023388 kB
Buffers: 23920716 kB
Cached: 275403332 kB
SwapCached: 0 kB
Active: 59079772 kB
Inactive: 431064908 kB
Active(anon): 1593580 kB
Inactive(anon): 191649352 kB
Active(file): 57486192 kB
Inactive(file): 239415556 kB
Unevictable: 249700 kB
Mlocked: 249700 kB
SwapTotal: 0 kB
SwapFree: 0 kB
[...]
再来看下内存回收相关的信息, sar 的数据主要从/proc/vmstat 采集, 主要关注: • pgscank/pgscand - 分别对应 kswapd/direct 内存回收时扫描的 page 数 • pgsteal - 回收的 page 数 • %vmeff - pgsteal/(pgscank+pgscand)
要理解这些数据的具体含义, 需要对内存管理算法有一定了解, 比如这里的 pgscan/pgsteal 只是针对inactive list而言的, 在内存回收的时候可能还需要先把页面从 active list 搬到 inactive list 等. 如果这里有异常, 我们可以先把这当成入口, 再慢慢深入, 具体到这里的%vmeff, 最好情况就是每个扫描的 page 都能回收, 也就是 vmeff 越高越好。
#sar -B 1
11:00:16 AM pgscank/s pgscand/s pgsteal/s %vmeff
11:00:17 AM 0.00 0.00 3591.00 0.00
11:00:18 AM 0.00 0.00 10313.00 0.00
11:00:19 AM 0.00 0.00 8452.00 0.00
I/O
存储 I/O 的 USE 模型: • Utilization. 存储设备的利用率, 单位时间内设备在处理 I/O 请求的时间 • Saturation. 队列长度
我们一般关注这些部分: • %util - 利用率. 注意即使达到 100%的 util, 也不代表设备没有性能余量了, 特别地现在的 SSD 盘内部都支持并发. 打个比方, 一家旅馆有 10 间房, 每天只要有 1 个房间入住, util 就是 100%。 • svctm - 新版 iostat 已经删掉 • await/r_await/w_await - I/O 延迟, 包括排队时间 • avgrq-sz - 平均 request size, 请求处理时间和大小有一定关系, 不一定线性 • argqu-sz - 评估 queue size, 可以用来判断是否有积压 • rMB/s, wMB/s, r/s, w/s - 基本语义
资源粒度
当我们判断资源是否是瓶颈的时候, 只看系统级别的资源是不够的, 比如可以用 htop 看下每个 CPU 的利用率, 目标任务运行在不同 CPU 上的性能可能相差很大。
内存也有类似情况, 运行 numastat -m
Node 0 Node 1 Node 2 Node 3
--------------- --------------- --------------- ---------------
MemTotal 31511.92 32255.18 32255.18 32255.18
MemFree 2738.79 131.89 806.50 10352.02
MemUsed 28773.12 32123.29 31448.69 21903.16
Active 7580.58 419.80 9597.45 5780.64
Inactive 17081.27 26844.28 19806.99 13504.79
Active(anon) 6.63 0.93 2.08 5.64
Inactive(anon) 12635.75 25560.53 12754.29 9053.80
Active(file) 7573.95 418.87 9595.37 5775.00
Inactive(file) 4445.52 1283.75 7052.70 4450.98
系统不一定就是物理机, 如果产品跑在 cgroup, 那么这个 cgroup 是更需要关注的系统, 比如在空闲系统上执行如下命令:
#mkdir /sys/fs/cgroup/cpuset/overloaded
#echo 0-1 > /sys/fs/cgroup/cpuset/cpuset.cpus
#echo 0 > /sys/fs/cgroup/cpuset/cpuset.mems
#echo $$
#for i in {0..1023}; do /tmp/busy & done
此时从物理机级别看, 系统的 load 很高, 但是因为 cpuset 的限制, 竞争约束在 cpu 0 和 1 上, 对运行在其他 cpu 上的产品影响并不大。
#uptime
14:10:54 up 6 days, 18:52, 10 users, load average: 920.92, 411.61, 166.95
应用角度
系统资源和应用的性能可能会有某种关联, 但是也可以更直接地从应用的角度出发定位问题:
• 应用能使用多少资源, 而不是系统提供了多少资源, 这里面可能会有gap, 系统是个模糊的概念, 而应用本身却相对具体. 以上面cpuset为例, 物理机是个系统, cpuset管理的资源也可以成为系统,