Skip to content
返回构建教程

性能剖析

优化前测量——用剖析器找真实瓶颈而非猜测。

为什么

无测量优化是赌博。开发者'知道' DB 慢加缓存——但真瓶颈是缓存帮不了的 N+1 ORM 查询,现又加脏数据 bug。剖析器(CPU、火焰图、APM trace)精确显时间去哪:60% serializeUser、30% DB、10% render。修 serializeUser(3 行改)得 2 倍速;无剖析你花一周做缓存。规则:剖析、找顶项、只修那、重剖析。重复。这比'优化一切看似慢的'快 10 倍。

何时使用

用户操作慢于目标时(如 API > 200ms、页 > 2s)。剖析+修约 30-60 分钟。已达标操作可跳过。

如何做

1. 定义目标并测当前
   - "结账 API 须 < 200ms p95";测:850ms p95
   - 用生产 trace 非本地合成——本地无真实数据量

2. 捕慢路径剖析
   - Node:--cpu-prof 标志,用 clinic.js 或 0x 检视
   - 浏览器:Chrome DevTools Performance 标签,录交互
   - DB:慢查询 EXPLAIN ANALYZE

3. 读火焰图 / trace 找最大条
   - 忽 10% 下——修 2% 瓶颈不动 p95
   - 记函数名和行

4. 仅修那一瓶颈——一改一 PR
   - 常见赢:N+1 → join、同步 JSON.parse → 流、缺索引、纯函数 memoize
   - 重测:p95 降?否则修无效——回退重剖析

5. 达标即停——勿镀金
   - "够快"是真条;进一步优化递减回报增复杂度

示例

# 慢 API 的 Node CPU 剖析
node --cpu-prof --cpu-prof-name=checkout.cpuprofile server.js
# 然后载 checkout.cpuprofile 入 chrome://inspect → CPU profiler

# 0x 火焰图(一命令,开浏览器)
npx 0x server.js
# 打慢端点,Ctrl+C → 0x 生 flamegraph.html

# Postgres——找慢查询及其计划
EXPLAIN ANALYZE SELECT * FROM orders o JOIN items i ON i.order_id = o.id WHERE o.user_id = 42;
# Seq Scan on orders (cost=0..8500 rows=10000)  ← 缺索引!
CREATE INDEX idx_orders_user_id ON orders(user_id);
# 重跑 EXPLAIN ANALYZE → Index Scan,8ms

常见问题

  • ⚠本地 10 行剖析,'修'prod 规模(1M 行)不存在的瓶颈。
  • ⚠一 PR 优化 5 处,见 30% 赢不知哪个驱动——后回归。
  • ⚠剖析前加缓存,藏真瓶颈(N+1)并引脏数据 bug。
  • ⚠过目标镀金——p95 180ms(目标 200ms)花一周到 120ms 用户感知不到。

最佳实践

  • ✓剖析生产(或真实数据量 prod-like staging)——本地剖析撒谎因数据形状错。
  • ✓每 PR 一优化,描述含前后 p95,赢可归因可审。
  • ✓设 SLO 预算(如 p95 < 200ms),耗 50% 预算告警——用户注意前抓回归。
  • ✓每修后重剖析;瓶颈移动,第二大条现是应修的。