性能剖析与优化套装
10 件套,给那个盯着一个 8 秒慢查询、卡顿 UI、或者慢接口发呆的工程师:先 baseline,再读火焰图,再修一条热路径,再回归压测 — 用 AI agent 读 profile,不是瞎猜。
这个 pack 包含什么
这是给那个被 @ 的工程师用的:「/search 接口要 8 秒,能看一下吗?」或者「这个 dashboard 一打开卡两秒。」10 件套,每件在五步闭环里有明确角色:baseline → 剖析 → 诊断 → 修一处 → 回归压测。
每个工具都是开源或有覆盖整个闭环的免费档。零「请联系销售」、零 SaaS-only 遥测。AI agent(Performance Profiler / GraphQL Performance Optimizer / Postgres MCP Pro)读的是真正的 profile 输出 — 不是看你代码瞎猜「这里加个索引吧」。
推荐安装顺序
- Claude Code Agent: Performance Profiler — 编排者。第一个装,因为后面你会把火焰图和 trace 都喂给它。它分得清 CPU profile / off-CPU profile / wall-clock profile 的区别,不会在 GC pause 是瓶颈时给你建议「加个缓存」。
- Lighthouse — 前端 baseline。动手前先跑
lighthouse https://your.url --output html,存下报告。后面每次改动都重跑做 diff。这是你的前端「之前的样子」。 - Size Limit — JS 包体性能预算。第一天就接 CI。配好
size-limit: [{ path: 'dist/*.js', limit: '200 KB' }],后面每个让 bundle 膨胀的 PR 在合并前被卡。整套里最便宜的性能收益。 - FlameGraph — Brendan Gregg 的 perl/SVG 火焰图生成器。生态里其他工具说的就是这个文件格式。装一次,pack 里其他 profiler 都能往里灌:
perf script | stackcollapse-perf.pl | flamegraph.pl > out.svg。 - async-profiler — JVM 低开销采样剖析器。给 Java/Kotlin/Scala 服务用。生产环境 ~1% 开销,输出的 collapsed-stack 格式直接进 FlameGraph。CPU / 内存分配 / 锁竞争 / wall-clock 一个工具全包。
- BCC (BPF Compiler Collection) — Linux eBPF tracing。瓶颈在你 runtime 之下时用这个 — syscall / 磁盘 I/O / 网络 / 缺页。
biolatency/tcpretrans/funccount是你最先用的三条命令。 - Grafana Pyroscope — 持续 profiling 后端。修完一个慢接口后装它,让下一次回归是 dashboard 上的火焰图 diff,不是凌晨 11 点的 Slack 消息。原生兼容 FlameGraph 格式。
- Postgres MCP Pro — 索引调优 + 安全 SQL MCP。「查询慢」就用它 — 把这个 MCP 挂到 Postgres 上,让 agent 解释执行计划,它会跑真实
EXPLAIN ANALYZE+ 给索引建议,并且自己再跑一次EXPLAIN验证过。不是幻觉。 - Claude Code Agent: GraphQL Performance Optimizer — 给每个 GraphQL gateway 早晚都会撞上的 N+1 问题准备的。读你的 resolver,找未 batch 的 DB 调用,按你的 schema 给具体的 DataLoader 修复方案。
- k6 — JavaScript 脚本驱动的压测工具。回归保护网。每次修完,对 staging 跑同一份 k6 脚本,比 p50/p95/p99。如果你用 k6 脚本复现不了那个慢路径,就证明不了你修好了。
它们怎么协同
┌─ BASELINE ─────────────────────────┐
│ Lighthouse(前端) │
│ k6(后端 p50/p95/p99) │
│ Size Limit(CI 里的包体预算) │
└─────────────┬──────────────────────┘
│ 「确实慢 — 但慢在哪?」
▼
┌─ PROFILE ──────────────────────────┐
│ async-profiler(JVM) │
│ BCC / eBPF(syscall、I/O) │
│ Pyroscope(生产持续采集) │
│ → 都输出 FlameGraph 格式 │
└─────────────┬──────────────────────┘
│ flamegraph.svg
▼
┌─ DIAGNOSE(agent 读 profile)──────┐
│ Performance Profiler agent │
│ Postgres MCP Pro(查询计划) │
│ GraphQL Performance Optimizer │
└─────────────┬──────────────────────┘
│ 「热路径是 X,修法是 Y」
▼
修一条热路径
│
▼
┌─ REGRESSION TEST ──────────────────┐
│ k6(重跑同一脚本,比 p95) │
│ Lighthouse(重跑,比分数) │
│ Pyroscope(火焰图 diff) │
└────────────────────────────────────┘
闭环不可妥协。**跳过 baseline 就证明不了修好了。**跳过火焰图就是瞎猜 — 而且 LLM 会猜得更狠。跳过回归,下次发布静默地把它改回去你都不知道。
你会遇到的取舍
- Pyroscope vs 一次性 async-profiler 抓 — Pyroscope 是持续的(常开、低开销、吃存储)。async-profiler 是按需的(怀疑时跑 60 秒,空闲零开销)。先用 async-profiler;修过两次回归、想让第三次从 dashboard 一眼看到,再装 Pyroscope。
- BCC vs
perf— BCC 更高层,用 Python 写脚本(可读)。perf是内核自带的剖析器,更底层、略更通用。BCC 是更友好的入口;需要 BCC 没暴露的特定事件源时再上裸perf。 - Lighthouse 本地跑 vs LH-CI — 本地 Lighthouse 是一次性的。Lighthouse-CI 在每个 PR 上跑并存趋势。修完第一个之后装 LH-CI;否则本地够用。
- Size Limit vs Bundlephobia/Webpack Bundle Analyzer — Size Limit 在回归时卡 CI(主动)。分析器只展示你的 bundle(被动)。两个都有用;Size Limit 是阻止下一波 50 KB 意外膨胀的那个。
- k6 vs Artillery vs Locust — k6 赢在脚本人体工程学(真 JavaScript,不是 YAML)、内置 p95/p99 报告、Grafana 集成。团队 YAML 派选 Artillery;团队 Python 派选 Locust。
常见踩坑
- 在 dev 剖析,给 prod 修 — 你笔记本 CPU 更快、数据集更小、JVM 还在解释模式。永远在贴近 prod 负载的环境里剖析。 Pyroscope 在 prod 抓胜过 async-profiler 在笔记本抓,每次都赢。
- 把火焰图当调用树读 — 火焰图是采样的栈。宽度 = CPU 时间,不是调用次数。一块很宽不代表「被调了很多」,代表「在那里花了很多 CPU」。
- 不给 LLM 看 profile 就让它优化 — 每个不带实测数据的「优化这段代码」prompt 返回的都是通用建议(「加 memoization」「改用 Set」)。把火焰图或
EXPLAIN ANALYZE直接喂给 agent。这就是 Performance Profiler agent 和 Postgres MCP Pro 存在的理由。 - 修了冷路径 — 80% 的「优化」改的是只占 0.1% 运行时间的代码。改之前先确认那个函数真的在火焰图 top 5 里。
- 修完没回归测 — 如果你用 k6 脚本(或 SQL 复现)回放不了那个慢路径,下次重构就会把它静默改回去,两周后才有人发现。
10 个资产打包就绪
常见问题
我现在就有一个慢接口,先用哪个?
先用 k6 打一个数(「p95 是 8.2s」)。然后在 k6 压它的同时用 async-profiler(JVM)或 BCC(Linux 任意)抓 60 秒火焰图。把火焰图 + 慢查询(从 DB 日志拿)一起喂给 Performance Profiler agent 或 Postgres MCP Pro。这就是完整的第一轮修复闭环 — 基础设施可达的话,约 45 分钟。
async-profiler 和 Pyroscope 真的两个都要装吗?
修第一个问题时,不用。async-profiler 一个就够按需抓,FlameGraph 工具渲染输出。修第二次回归时再装 Pyroscope —— 当你意识到不想每次都 SSH 进去 attach。持续 profiling 在第三次事故后开始回本。
为啥要专门的 GraphQL 优化 agent,不直接用通用 Performance Profiler?
GraphQL 的 N+1 问题是个结构反模式,火焰图里不容易看到 — 慢的部分是很多个快查询,单个都看不见。GraphQL Performance Optimizer agent 直接读 resolver 代码,找未 batch 的 DB 访问,按你的 schema 形状给 DataLoader 修复建议。通用 profiler 会告诉你「DB 调用宽」,但不会告诉你「这个 resolver 一个请求扇出 200 次调用」。
BCC 能在 macOS 上跑吗?
不能。BCC 基于 eBPF,只在 Linux 内核上跑。macOS 上原生代码用 Instruments(Xcode 自带),JVM 用 async-profiler。本 pack 假设 prod 在 Linux —— 即使你笔记本不是,大多数服务器是。
Size Limit 第一天的预算设多大合适?
量一下当前 bundle 大小,向上取 10%,把这个值设为 limit,然后发布。目标是挡住未来的膨胀,不是从英雄式节食开始。CI 绿了、团队习惯在 PR 上看 Size Limit 评论之后,每月把 limit 往下调 5%。多数团队一个季度内会发现 bundle 里 30-40% 是死重。