mcpField
P
perf-workflow

perf-workflow

github.com/fudesign2008开发644 次安装今天更新
代码仓库

关于 perf-workflow

perf-workflow 是一套循序渐进的性能问题分析技能,帮助开发者从证据定位瓶颈、验证根因,并完成优化与验证闭环。它强调可复现数据、全链路分析和单变量验证。

主要功能

  1. 01按证据、定位、假设、监控、优化、验证推进
  2. 02从用户操作追踪完整执行链路
  3. 03结合耗时与资源数据筛选瓶颈
  4. 04要求根因假设可证伪且可复现
  5. 05支持开关控制的长期性能监控

适用场景

  1. 01分析页面卡顿或主线程阻塞
  2. 02定位慢 API 或后端请求瓶颈
  3. 03调查内存增长与疑似泄漏
  4. 04为间歇性性能问题补充监控

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/fudesign2008/open-skills --skill perf-workflow

安装后在 Claude Code 中输入/perf-workflow确认已加载。

详细介绍

性能问题分析工作流

强依赖:clarifying-question-discipline(严格的主动提问规范)和 known-issue-research(已知性能模式快速检索,§2.1)。如果缺少其中任一项,则中止并打印安装命令(npx skills add FuDesign2008/open-skills -g --skill '*' --yes)。

范围

此工作流负责找出性能瓶颈的根本原因:是谁触发了什么高开销操作,以及在什么条件下触发。确认根本原因后,可据此设计修复方案、实施代码/配置优化并验证结果。 如何发布、推出或交付修复不在此工作流的范围内——由项目自行决定。

触发识别

所有触发词都以「性能」开头,因此很容易识别和记忆。单独说出触发词,或使用**「触发词 + 冒号 + 空格 + 描述」**的形式,即可进入此工作流或相应阶段。使用冒号时,冒号和空格不受语言限制(中文或英文标点均可)。

  • 「性能分析」或「性能分析: xxx」 → 进入此工作流,从阶段 1(收集证据)开始
  • 「性能证据」或「性能证据: xxx」 → 阶段 1:收集证据
  • 「性能定位」或「性能定位: xxx」 → 阶段 2:定位瓶颈
  • 「性能假设」或「性能假设: xxx」 → 阶段 3:推测根本原因
  • 「性能监控」或「性能监控: xxx」 → 阶段 4:构建监控
  • 「性能优化」或「性能优化: xxx」 → 阶段 5:实施优化
  • 「性能验证」或「性能验证: xxx」 → 阶段 6:验证
  • 「性能深入」或「性能深入: xxx」 → 在阶段 2(定位瓶颈)中继续或深入分析

当用户说「性能问题」("performance issue")、「卡顿」("stutter/jank")、「很慢」("it's slow")等时,也可视为进入此工作流,从阶段 1(收集证据)开始。 当用户提供与性能相关的日志或性能分析结果并希望进行分析时,视为进入此工作流,从阶段 1(收集证据)或阶段 2(定位瓶颈)开始。


总体原则

「先定问题拆链路,再采数据筛瓶颈,下钻推导提假设,控制变量验根因,优化固化成闭环。」(先明确问题并拆解链路;再收集数据、筛选瓶颈;深入分析并推导假设;控制变量验证根因;最后将优化固化为闭环。)

  1. 数据驱动:先获取数据,再得出结论——绝不要先假设问题,再搜寻支持证据。如果没有复现路径或可分析的数据,先帮助用户收集这些信息(复现步骤、日志、性能分析数据、屏幕录制等)。
  2. 自顶向下:从用户感知到的完整链路入手,先宏观后微观。先确定慢在哪里(耗时/阻塞/渲染量等),再追溯是谁触发的,以及触发的条件是什么。
  3. 单一变量,可复现:根因假设必须能够通过现有数据或少量有针对性的监测手段得出是/否结论。验证时一次只改变一个变量;结果必须可复现、可证伪——绝不把相关性当作因果关系。
  4. 覆盖完整链路:分析从问题开始到结束的完整执行链路,而不只是局部数据——避免盲人摸象。
  5. 可开关、适用于生产环境的监测:性能可观测性应设计为代码库中完善且适用于生产环境的监测能力,并通过开关(环境变量、配置项、功能标志等)控制。关闭时,不输出任何内容,也不采集任何样本,且不影响线上产品;需要分析时,打开开关即可收集数据——无需临时添加监测代码,之后再将其移除。
  6. 不要过早优化:只优化那些有数据支撑、影响用户体验且超过阈值的性能问题。对于没有测量数据支撑的「可能有一天会出现的性能问题」,不要进行预防性优化——这只会增加不必要的代码复杂度和维护成本。
  • ⚠️ 主动询问:遵循 clarifying-question-discipline(每轮只问一个问题;多轮沟通,直到问题明确;先澄清,不要急于回答;强依赖——如果缺少必要信息就中止)。
  • 🚩 红旗:一次性向用户抛出多个问题/待确认事项,让用户逐一回答(违反硬性规范)——每次只问一个最关键的问题,收到答复后再问下一个。

阶段流程

前进流程:证据 → 定位 → 假设 → 监测 → 优化 → 验证。

常见跳转:

  • 阶段 1 发现缺少数据,需要建立监测 → 直接进入阶段 4(建立监测)添加监测,然后返回阶段 2。
  • 阶段 2 已有足够数据且瓶颈明确 → 跳过阶段 3,直接进入阶段 4 或 5。
  • 阶段 6 否定了假设 → 返回阶段 2 或 3 重新分析。
  • 阶段 6 表明优化效果未达预期 → 返回阶段 3 重新提出假设,或返回阶段 5 调整优化方案。
  • 阶段 1 难以采集间歇性问题的数据 → 优先进入阶段 4 建立长期监测;问题复现后,再返回阶段 2。

阶段 1:收集证据(性能证据)

目标

获取可复现、可分析的性能数据,而不是仅凭描述猜测;将模糊的「卡顿/缓慢」转化为量化指标和性能基线,并明确优化目标和硬性红线。

需要澄清的信息
  • 症状:是什么操作触发了变慢(点击、滚动、输入、拖动、API 请求等)?“慢”具体表现是什么(卡顿、空白屏幕、加载指示器、无响应)?尽可能量化(例如,某个端点的 P99 耗时,单位为毫秒;某项操作的帧率或延迟),并明确分析边界(问题的起点和终点,避免范围无限扩大)。
  • 现有数据:是否已有日志、Performance/CPU 性能分析记录、网络抓包或自定义埋点?如果没有,先确定可以“在什么环境中、用什么方法”采集数据。
  • 复现条件:问题总是可以复现,还是偶尔发生?是否对数据量、并发量或设备有要求?
常见数据来源(按场景选择)
场景候选数据来源
前端卡顿 / 主线程阻塞控制台日志、Chrome Performance 录制、Long Task / 自定义性能监控
渲染过多 / 重绘开销大框架渲染统计、React DevTools Profiler、自定义提交/渲染埋点
API 响应慢 / 后端问题网络面板、服务端日志、APM、追踪记录
内存问题 / 泄漏堆快照、内存趋势图

不绑定任何特定技术栈,应根据项目实际具备的监控能力和工具进行选择。

输出
  • 清楚说明已有哪些数据,以及仍缺少哪些数据。
  • 如果缺少数据:明确用户需要执行的操作,以及需要采集的内容(例如,提供复现步骤、切换某个开关、复现问题,并导出控制台或性能分析结果)。
  • 建议包含的输出:症状(含量化指标)、复现条件、分析边界、当前性能基线,以及目标阈值或红线;可整理为结构化的“性能问题定义表”,便于后续对比。

阶段 2:定位瓶颈(性能定位)

目标

从原始数据中找出异常(谁消耗了多少时间/资源,以及发生在何时),并追踪触发链路(事件 / 调用栈 / 数据流);构建从起点到终点的完整链路拓扑,并从时间和资源两个维度进行初步瓶颈筛查,将分析范围缩小到 1~2 个核心环节。

分析方法(通用)
  • 全链路拓扑:按执行顺序,将从用户操作到问题结束的每个环节逐一拆解(代码执行、系统调用、网络/存储等),形成无缺漏、无重叠的拓扑;每个环节都应可独立计时,并明确输入/输出。
  • 二维采集:时间维度(各环节耗时、占整个链路的比例)+资源维度(CPU/内存/IO/网络等)——两者缺一不可。
  • 初步瓶颈筛查:按耗时占比对各环节排序,锁定高耗时环节(例如占比 >20%);根据资源异常(饱和、持续上升、错误率)锁定异常环节;排除耗时低且资源正常的环节。资源利用率 >70% 是常见的告警线——超过此阈值后,响应时间往往会非线性上升,因此即使绝对值看起来不高,也值得优先排查。
  1. 发现异常 在时间线或汇总统计中,找出显著异常的指标,例如:

    • 某个任务/请求的耗时超过阈值(例如主线程任务 >50ms、>200ms);
    • 单次操作的处理量异常大(例如一次更新触及大量节点、一次请求返回超大数据负载);
    • 触发频率异常高(例如某个事件的触发次数远超预期)。
  2. 定位异常 对于每个异常,确定:

    • 异常发生在哪一层(前端/后端/网络/存储);
    • 对应的代码或模块(文件、函数、组件、端点);
    • 调用栈或事件链(从用户操作或入口到耗时/资源消耗点)。
  3. 构建因果链 将其串联为“用户操作 → 事件/请求 → 处理函数 → 高耗时操作 → 观测到的指标”,避免只看到症状,却找不到触发条件。

工作方法
  • 对于文本日志:按关键词、耗时、错误码等使用搜索工具(grep/ripgrep 等)筛选,然后阅读相关片段和调用栈。
  • 对于性能剖析数据:先查看时间线或火焰图上的“宽条”或“高占比”区域,再深入到具体函数/组件。
  • 对于代码:阅读代码并搜索调用关系,同时交叉参考日志中的栈信息,弄清楚“谁在什么条件下调用了谁”。
输出
  • 异常摘要:说明哪里耗时高/处理量大/频率高,以及大致位置。
  • 因果链:用一两句话或简单图示描述“操作 → … → 瓶颈”。
  • 待验证假设(初步方向):列出 1-3 个“可能的根因”方向,并说明每个方向有哪些证据可以证实或证伪。细化和分类将在第 3 阶段(假设根因)进行。
  • 核心瓶颈环节列表:列出 1-2 个环节,并附上耗时占比或资源异常摘要。
已知性能模式快速检索(可选,定位卡顿时使用)

当满足 known-issue-research §2.1 的触发条件时,加载该技能并遵循 §2.1(性能模式变体)。本工作流自身的模式表和阶段编排仍保留在此文件中。


第 3 阶段:假设根因(性能假设)

目标

将异常和触发链提炼为可验证的根因假设,并根据常见性能问题模式对其分类,以指导后续的埋点和修复。假设必须可验证、可证伪——不能含糊猜测;可借助行业方法进行分类(见下文)。

根因分析参考
  • USE 方法(资源类型瓶颈):从三个维度判断资源是否饱和(CPU、内存、IO、网络)——利用率、饱和度、错误。
  • RED 方法(执行/请求类型瓶颈):从三个维度判断执行逻辑或调用链问题——速率、错误、耗时。

将这些方法与下方的“常见模式”表结合使用;此处不再展开具体步骤。

常见模式(与技术无关的描述)
模式特征典型诱因
响应范围过广原本只应局部更新,却触发全局或大范围的重新计算/重新渲染粗粒度事件(例如“任何变化”)触发了大范围更新;缺少细粒度订阅或差异比较
更新未批处理/合并一次操作导致多次独立的重新计算或重新渲染多次连续的状态更新未批处理;异步回调各自触发更新
高频触发高频事件每次发生时都会执行开销较大的逻辑scroll/resize/mousemove 等事件未进行节流/防抖;每一帧或每次事件都进行大量重新计算
积压任务同时触发主线程繁忙或队列积压时,许多延迟任务同时触发多个节流/防抖计时器在同一时刻触发;计时器/微任务不断堆积
资源泄漏内存/连接/句柄持续增长且从未释放连接未关闭、缓存/计时器未清理、监听器未移除
同步阻塞同步操作长时间占用主线程或关键路径同步 I/O、锁竞争、长事务、开销较大的同步计算
重复/冗余计算未使用缓存而反复计算同一结果缺少记忆化/缓存、N+1 查询、重复序列化/反序列化

在具体项目中,这可能表现为“某个框架的 setState”“某个事件总线的 emit”“某个 RPC 调用”等,但在抽象层面上,它们都属于上述类别。

输出
  • 当前最可能的 1-2 个根因假设;每个假设都必须可验证且可证伪(例如,通过判断“是否进行了全表扫描?”或“这个变量的值是多少?”得出是/否结论),避免使用“查询很慢是因为 SQL 写得不好”这类无法验证的表述。
  • 如果有多个假设,按“用户感知影响最大 + 验证成本最低”排序,并优先验证排名最高的假设。
  • 每个假设的验证方法:现有日志能否给出答案?如果不能,需要在路径的哪些位置添加可切换的监控(参见阶段 4:构建监控)?确认根因后,进入阶段 5(实施优化)进行修改,然后在阶段 6(验证)中验证假设和优化效果。

阶段 4:构建监控(性能监控)

目标

当现有数据无法验证假设时,在关键路径上添加可切换、达到生产级别的性能可观测性。监控逻辑作为真实代码发布,并由开关控制;关闭时不会影响线上产品,开启后则可用于分析性能监控数据。

何时需要额外监控
  • 现有日志/性能分析数据无法显示“是谁触发的”“在什么条件下触发”或“当时某个变量的值是多少”。
  • 需要比较“假设成立”和“假设不成立”时的行为(例如某个标志为 true 与 false 时的行为)。
  • 项目尚未为这条路径配置可切换的性能监控,需要设计并发布此监控。
监控设计原则(通用)
  1. 由开关控制 使用运行时开关(环境变量、配置中心、功能标志、本地调试开关等)控制是否启用。生产环境中默认关闭,或仅对特定用户/会话启用;排查问题时再打开,避免给普通用户带来开销或噪声。

  2. 长期保留,而非临时使用 监控代码是长期保留的功能,而不是“添加后验证,再删除”。逻辑长期保留,行为完全由开关控制:关闭时不产生输出、不采样,也没有额外开销(或开销可忽略);开启时则按约定格式输出或上报,并与现有日志/性能分析记录保持一致。

  3. 便于对齐 输出稳定的时间戳(例如 performance.now() 或服务端纳秒级时间)和位置标识符,以便与同一时间线上的现有日志/性能分析记录对齐,进行因果关系和时序分析。

  4. 信息恰到好处 每条记录至少应包含:位置标识符、时间戳,以及用于确认或证伪假设的少量关键变量(例如命中了哪个分支、ID、计数或错误代码)。尽可能复用项目现有的性能日志格式,保持分析方式一致。

选择监控点
  • 优先:疑似的直接触发点(例如更新状态的调用、触发请求的调用、执行重新计算的函数入口)。
  • 其次:触发链上的中间节点(例如事件处理程序入口、回调入口),用于确认调用顺序和频率。
  • 然后:耗时计算的入口/出口,用于确认每次调用的耗时和调用次数。
输出
  • 监控点列表(文件:行号或函数/端点名称),每个监控点都要注明用途和建议的开关名称。
  • 用户需要采取的操作:如何启用开关、如何复现,以及如何捕获并提供新的日志/性能分析记录。
  • 如果根因已经确认,或将在 Stage 6 中验证,请进入 Stage 5(实施优化)进行更改。

Stage 5:实施优化(性能优化)

目标

根据 Stage 3 的根因结论(以及 Stage 4 的监控结果;如果已在 Stage 6 中验证假设,也可据此实施),进行代码或配置层面的优化,以消除或缓解瓶颈。本阶段仅产出“针对根因的更改”及更改列表;多方案评估或详细任务拆分不在本阶段范围内。

原则
  • 修复根因,而非表象:更改应对应 Stage 3 中识别的根因模式(例如缩小响应范围、批量更新、节流/防抖),而非泛泛地进行优化。
  • 利用监控进行对比:优先使用 Stage 4 中可由开关控制的监控,在 Stage 6 的相同复现场景下对比更改前后的情况,确认更改确实有效。
  • 控制变量验证:更改前先通过单变量实验验证根因;每次优化只针对一个根因点,以便 Stage 6 将收益归因于单项更改。
  • 分层并考虑成本效益:按从高到低的层级考虑——业务逻辑 → 应用代码 → 框架/依赖项 → 系统/硬件,优先选择较高层;优先选择“更改成本低、收益高”的方案(例如简化逻辑、复用缓存)。
  • 按时间占比排序:优先优化时间占比最高的部分;时间占比低于 10% 的部分即使性能提升 100 倍,对整体指标的影响也微乎其微,因此应跳过,聚焦真正的主要瓶颈。
  • 稳定性:不要改变业务语义、引入功能缺陷或产生新的性能副作用。
输出
  • 变更清单:文件、位置(函数/模块)、变更摘要。
  • 建议的验证方法:说明应使用哪个复现场景,以及要监控哪些指标(与第 4 阶段的监控保持一致),以便第 6 阶段验证优化效果。

第 6 阶段:验证(性能验证)

目标
  1. 使用新数据,对第 3 阶段(提出根因假设)中的假设作出是/否判断;必要时修正假设,或返回第 2 阶段(定位瓶颈)。
  2. 如果已完成第 5 阶段(实施优化),则使用相同的复现场景和第 4 阶段的监控数据进行优化前后对比,确认优化是否有效,以及指标是否达到目标。
验证方法
  • 对每个假设,明确说明“如果假设成立,日志/性能分析结果应显示什么”和“如果假设不成立,应显示什么”。
  • 在新日志中搜索相应模式,并检查其是否符合假设成立时的预期。
  • 如果有时间戳,将不同模块/层的埋点对齐到同一时间线上,确认事件顺序,以及它们是否发生在同一任务/请求中。
  • 优化后,在相同的复现路径下对比优化前后的关键指标(耗时、调用次数、渲染量等),并说明通过标准。
  • 效果验证(已完成第 5 阶段时):
    • 基线复测:在与优化前相同的复现条件和环境下,对比全维度指标。
    • 功能回归:确认常规、边缘情况和峰值负载场景仍能正常工作。
    • 副作用检查:确认没有引入其他性能问题(例如通过缓存优化响应时间,却导致内存占用上升)。
    • 如果可行:通过生产环境/金丝雀发布验证真实流量下的效果。
输出
  • 每个假设的结论:已确认 / 已推翻 / 仍不确定。
  • 如果仍不确定:说明还缺少哪些信息,以及下一步是添加可切换的监控以收集更多数据,还是从不同角度重新分析。
  • 如果已确认:用一两句话概述根因(谁在什么条件下触发了什么),作为设计和实施修复方案的依据。
  • 如果已完成第 5 阶段(实施优化):报告优化前后对比,以及是否达到目标。
  • 闭环(可选后续步骤):验证通过后,可考虑将关键指标纳入常态化监控和告警;如果有 CI/CD,可考虑在流水线中添加性能基线或门禁以防止回归;并将此次优化的指标和最佳实践纳入团队规范,以持续改进。
  • 停止条件:一旦所有假设都已验证且关键指标达到目标,或继续优化剩余瓶颈的性价比过低(变更成本远高于收益),本轮优化即可结束。

输出详细程度(自适应)

  • 问题简单、数据充足:可精简为“异常 + 因果链 + 根因结论”。
  • 问题复杂、涉及多个模块:简要输出各阶段的结果(收集了什么、主要异常、假设、监控点列表、优化要点、验证结论和效果结论),并在必要时附上关键日志片段或调用栈摘录。
  • 涉及特定技术栈时,在该次交流中自然地结合相关内容,不要在此 SKILL 文件中硬编码特定标签或命令。

评论

支持 Markdown