☰ 第 05 章 · 应用程序:从工作负载开始
COURSE SOURCES

参考来源与版权说明

仅作来源说明 · 不提供原始资料下载
查看全部来源说明
01
START HERE

这章解决什么问题

资源指标能告诉你应用消耗了什么,却未必说明应用为何做这些工作。应用层离业务操作最近,往往拥有最大的优化空间:消除无用请求、选择更合适的算法、减少小 I/O、改善缓存、调整并发模型,通常比在内核末端微调收益更高。本章建立“业务操作 → 线程状态 → 代码路径 → 系统资源”的分析链。

开始前要回答应用做什么、服务哪些请求、SLO 是什么、如何配置、运行在哪种主机/配额内、有哪些指标与日志、版本和已知问题是什么。没有目标,CPU 降低 10% 也无法判断是否值得;有目标,才能选择优化延时、吞吐量、资源效率还是成本。

02
SECTION 02

五条核心结论

  1. 从业务操作和目标开始。 请求类型、速率、延时分布和错误比“进程有点忙”更可行动。
  2. 先分 on-CPU 与 off-CPU。 前者通过 CPU 剖析解释,后者再分为调度、I/O、锁、睡眠和等待工作。
  3. 优化常见路径。 火焰图最宽的代码路径、最高频系统调用和主要等待状态,比随机阅读源代码更值得先看。
  4. 并发不等于并行。 多线程可隐藏 I/O 等待;真正同时使用多颗 CPU 还需并行,并会引入同步与调度成本。
  5. 可观测性本身是长期性能能力。 有清晰指标、符号和栈的应用,更容易发现并消除无效工作。
03
SECTION 03

核心模型与关键指标

一次请求的墙钟时间
├─ on-CPU
│  ├─ 用户态:算法、解析、压缩、GC、运行时
│  └─ 内核态:系统调用、中断相关路径
└─ off-CPU
   ├─ 等待 CPU(可运行)
   ├─ 磁盘/网络/缺页
   ├─ 锁与条件变量
   ├─ 主动睡眠
   └─ 空闲等待下一项工作

关键指标包括请求率、错误率、延时的中位数与尾部;进程/线程用户和系统 CPU;可运行队列延时;I/O 尺寸、方向、次数与持续时间;系统调用类型和速率;锁竞争与持锁时间;线程池繁忙比例、排队长度、拒绝数;缓存命中率、GC 暂停、文件描述符与连接池使用量。

应用技术存在权衡:较大 I/O 能摊薄固定开销,却可能增加不需要的数据和单次延时;缓冲写提高吞吐量,却会增加等待;轮询可降低事件到达后的响应时间,却消耗 CPU;更多线程能增加并行度,也可能扩大上下文切换、缓存争用与锁竞争。

04
SECTION 04

诊断步骤

  1. 选择一个具体操作和 SLO,按请求类型记录速率、错误与延时分布,确认工作负载是否改变。
  2. 检查线程池、连接池、队列、缓存和资源限制,识别饱和、拒绝、降级模式与异常配置。
  3. 将处理请求的线程时间分为用户、内核、可运行、换页、磁盘、网络、睡眠、锁和空闲九类;先确定最大非空闲状态。
  4. on-CPU 高时,采样用户+内核栈并看火焰图最宽的塔;调查高层调用者与顶部直接执行函数。
  5. off-CPU 高时,仅关注处理请求的线程或函数,排除正常等待工作的线程,再判断 I/O、锁还是调度延时。
  6. 内核时间或 I/O 可疑时,统计系统调用类型、次数、参数与持续时间;高频小 I/O、重试或短命进程常是直接线索。
  7. 分布式请求用 trace/span 找到占主要时间或报错的服务,再回到该服务执行上述单机分析。
  8. 修改后按相同请求组合复验延时、吞吐量和资源成本,防止用牺牲另一个目标换来局部改善。
05
SECTION 05

常用工具与命令

pidstat -p PID 1
pidstat -d -p PID 1
ps -L -p PID -o pid,tid,psr,stat,pcpu,comm
perf top -p PID
perf record -F 99 -g -p PID -- sleep 10
profile -F 49 -p PID 10
offcputime -p PID 5
strace -c -p PID

PID 替换为目标进程。前几项是观察型工具,但 perf top、采样和 BPF 工具仍有开销;profileoffcputime 是否存在取决于 BCC/BPF 安装与权限。strace 通过 ptrace 跟踪系统调用,在高系统调用率进程上可能造成巨大减速,只应在测试环境或明确评估风险后短时、限范围使用。选项随版本不同,以本机帮助为准。

06
SECTION 06

如何解读结果

  • pidstat%usr 高,优先剖析应用/运行时代码;%system 高,继续看系统调用、缺页、中断或内核路径。
  • 火焰图宽度代表样本占比,不是函数单次耗时或调用次数。先看宽塔,再沿下方祖先理解“谁触发了它”。
  • off-CPU 火焰图往往被线程池正常空闲淹没。必须过滤到请求处理函数、目标 PID/线程或合理的等待时长。
  • iodelayD 状态或文件系统函数只是方向;要证明业务影响,还需确认该请求同步等待这些事件。
  • 系统调用汇总中大量 read/write 要结合每次字节数;大量短调用可能意味着缓冲不足,也可能是协议本身需要。
  • [unknown] 或只有一两层的栈通常是符号/栈展开问题,不代表代码没有调用者。可用 debuginfo、保留帧指针或运行时专用剖析器修复可见性。
07
SECTION 07

常见误判

  1. 认为线程越多吞吐量越高。 锁、CPU 数、缓存和调度开销会让收益下降甚至反转。
  2. 把所有 off-CPU 都算成性能损失。 服务线程等待下一请求属于正常空闲,不能作为优化目标。
  3. 只看用户态剖析器。 它可能看不到内核时间和被取消调度的时间,造成墙钟时间解释不完整。
  4. 把大 I/O 当通用优化。 随机小读若被放大,会浪费带宽、缓存和延时。
  5. 用 `strace` 得到慢结果后怪应用。 观测器自身可能改变系统调用时序,应先量化开销。
  6. 看到缺失符号就猜函数。 先修复符号和栈,再作代码级结论。
08
SECTION 08

五分钟自测

  1. 为一个 Web 接口写出延时、吞吐量和资源效率三个不同目标。
  2. 线程处于可运行、磁盘等待、锁等待时,下一步各看什么证据?
  3. CPU 火焰图中宽框与高框分别表示什么?
  4. 为什么完整 off-CPU 火焰图常被“正常等待”主导?
  5. 系统调用次数很多时,为什么还必须看尺寸、持续时间和调用栈?
09
SECTION 09

本章小结

应用性能分析要把资源消耗重新关联到业务请求。先确定目标和工作负载,再以线程状态把时间分到 on-CPU 与各种 off-CPU 原因;CPU 剖析、系统调用和等待栈随后解释具体代码路径。并发、缓存、缓冲和 I/O 大小都有收益与代价,任何优化都要回到同一 SLO、同一负载组合复验。

10
SECTION 10

来源定位

主题PDF 页码
应用上下文、目标、SLO 与可观测性224-228
算法复杂度、I/O、缓存和缓冲228-230
轮询、并发、并行、同步和非阻塞 I/O230-236
语言、运行时、JIT 与垃圾回收237-240
CPU/off-CPU、系统调用与 USE240-247
九种线程状态、锁和静态配置247-253
perf、profile、offcputime、strace 与 BPF 工具253-268
缺失符号和栈展开问题268-271
练习与参考资料271-273
📝
QUICK CHECK

章节测验

5 道单选题。答错有解析,答对看来源页码。

单选题 · 第 1/5
已答 0/5

应用请求的大部分墙钟时间不在 CPU 上,下一步最合理的是?

⚡ 用本章题目开始计时冲刺