性能工程与可观测性
性能优化的第一原则是测量:不测量就优化是猜。本章讲基准测试的陷阱、采样式剖析器与火焰图、可观测性三支柱与 SLO,以及 Amdahl 定律对优化收益的约束。
- 不测量就优化是猜:直觉的瓶颈通常错(真正的热点常在想象之外,→ 存储层次与缓存);
- 先测量,再假设,再验证:profiler 定位热点 → 针对性假设 → 改动后再测。
基准测试的陷阱
Section titled “基准测试的陷阱”- 预热:JIT(→ 运行时、内存管理与垃圾回收)与缓存需要预热,冷启动数字不可信;
- 平均值的谎言:延迟是长尾分布,平均值掩盖 p99(见下);
- 编译器删代码:基准里的"死代码"被优化掉(基准框架的陷阱,JMH 一类工具防);
- 环境噪声:共享 CPU(云主机邻居)、频率调节、NUMA——基准要隔离与多次重复。
剖析与火焰图
Section titled “剖析与火焰图”采样式剖析器(perf、py-spy、async-profiler):定期采样调用栈,统计热点——开销低(<1%),可上生产。火焰图(flame graph)把采样栈叠成矩形:宽 = 占用时间多——一眼看出热点路径。
剖析的两条纪律:
- 固定变量:一次只改一个东西,否则归因错误;
- 全栈采样:含内核态(系统调用、锁等待)——只看用户态会漏掉"时间花在内核"的真相。
p99 比平均值重要
Section titled “p99 比平均值重要”p99 比平均值重要:用户体验由尾部决定——1000 个请求里 10 个慢 5 秒,平均值几乎不变,但那 10 个用户不会回来。
- p50/p95/p99/p999:尾部延迟的分级观测;
- 尾延迟放大:一次页面请求串行调 10 个后端(每个 p99 = 100ms)→ 页面 p99 ≈ 1s——尾部的乘法效应(并行调用、hedged request 是对策);
- GC 停顿、缓存过期风暴、锁竞争是 p99 的常客(→ 运行时、内存管理与垃圾回收)。
可观测性三支柱
Section titled “可观测性三支柱”| 支柱 | 回答 | 成本 |
|---|---|---|
| 日志 | 发生了什么(细节、上下文) | 存储贵,采样与分级 |
| 指标 | 系统状态如何(数值时序) | 便宜,可告警 |
| 追踪 | 一次请求经过了哪里 | 采样(1–10%),上下文传播 |
- 结构化日志(JSON)+ 集中聚合(ELK/Loki);
- 指标:RED 方法(Rate、Errors、Duration)面向服务、USE 方法(Utilization、Saturation、Errors)面向资源;
- 分布式追踪:trace ID 沿调用链传播(OpenTelemetry 标准)——微服务的"这次请求慢在哪"只能靠追踪(→ 架构与权衡)。
三支柱的分工:指标发现"有问题"(告警),追踪定位"在哪一段",日志解释"具体为什么"。
SLO 与错误预算
Section titled “SLO 与错误预算”- SLI(指标:可用性、延迟)、SLO(目标:99.9%)、SLA(合同:违约赔偿);
- 错误预算: 的允许失败量——预算内的失败是允许的(用于发布与实验),预算烧完就冻结发布、专注可靠性——SRE 的核心机制:用预算把"稳定性 vs 迭代速度"变成可度量的决策。
Amdahl 定律
Section titled “Amdahl 定律”为可并行比例、 为核数——串行部分限制总加速比:95% 可并行的程序, 也只有 20 倍。含义:
- 优化前看占比:把 5% 的部分优化到零,上限就是 5% 的总收益——先优化占比大的;
- 扩展的极限:加核(扩容)的收益被串行部分(锁、协调、单点)封顶——与系统设计的"串行部分"(单点数据库、全局锁)对应(→ 系统设计工具箱)。
生产问题的定位流程
Section titled “生产问题的定位流程”- 指标告警(哪个服务哪个指标异常);
- 追踪定位(这次请求慢在哪一段);
- 剖析深挖(那段代码的热点在哪行);
- 日志取证(上下文与异常细节);
- 改动后验证(指标与 p99 回落)。
每个环节都有工具,工具链先于救火建好——可观测性是平时投入、火灾时救命的投资。
- 不测量就优化是猜;基准的陷阱:预热、平均值、死代码、环境噪声
- 采样剖析 + 火焰图:宽 = 时间多;全栈采样含内核态
- p99 比平均值重要;尾部有乘法效应(串行调用链)
- 三支柱分工:指标发现、追踪定位、日志解释;错误预算把稳定性变成可度量决策
- Amdahl 定律:串行部分限制总加速比——先优化占比大的