mcpField
P
performance-testing

performance-testing

github.com/petrkindlmann测试与质量2221.2k 次安装6 天前更新
代码仓库

关于 performance-testing

面向开发与 QA 团队的性能测试技能,涵盖后端负载测试和前端 Web 性能。它将 k6 阈值与 Lighthouse CI 断言用于 CI 门禁,并区分实验室指标和真实用户数据。

主要功能

  1. 01使用 k6 测试负载与吞吐量
  2. 02配置恒定、爬坡、突发和浸泡负载
  3. 03以阈值在 CI 中阻止性能回归
  4. 04通过 Lighthouse CI 检查 Web 性能预算
  5. 05测量 LCP、INP 和 CLS
  6. 06按步骤定位性能瓶颈

适用场景

  1. 01验证后端在预期流量下的表现
  2. 02在 CI 中阻止超出预算的构建
  3. 03检查页面核心 Web 指标
  4. 04排查性能预算超标的原因

安装

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

$npx skills add https://github.com/petrkindlmann/qa-skills --skill performance-testing

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

附带文件references/recipes.md

详细介绍

通过 CI 强制执行性能预算,衡量、断言并保障应用性能,而不是依赖主观的“感觉够快”评估。这项技能涵盖两个领域:**负载测试** (后端能否处理流量?)和**Web 性能**(前端对用户来说够快吗?)。 “LCP 为 3.2s”的报告只是信息;在 2.5s 时让 CI 门禁导致构建失败,才是真正的问责。

快速导航

你需要……前往
测试流量下的后端容量/吞吐量/延迟k6 负载测试 → references/recipes.md
选择负载模式(恒定/渐增/骤增/持续)负载配置表
衡量真实用户的前端速度(LCP、INP、CLS)Web 性能 + Core Web Vitals
在 CI 中设置页面性能门禁Lighthouse CI(设置 TBT 门禁,而非 INP——见下文)
超出预算,需要找出原因瓶颈识别
将现有测试套件从 k6 v1 迁移到 v2k6 v2 迁移提示框

调研问题

先检查 .agents/qa-project-context.md——如果文件存在,就使用其中的信息,并跳过已回答的问题。

衡量什么
  • Web 性能还是负载测试? Web 性能衡量用户感知到的速度(Core Web Vitals、页面加载)。负载测试衡量服务器容量(RPS、负载下的延迟)。大多数产品两者都需要。
  • 哪些用户旅程对性能至关重要? 并非每个端点都需要负载测试。重点关注流量大、对收入至关重要或对延迟敏感的流程。
  • 是否已有性能预算? 如果有,目标是什么?如果没有,这项技能可帮助建立预算——先测量基线。
当前状态
  • 当前基线是多少? 设定目标前需要有具体数据。先测量,再定义预算。
  • 过去有哪些性能问题? 导致用户流失的慢页面、负载下超时的端点、卡死的查询——这些都能指明重点。
  • 是否已有监控? APM(Datadog、New Relic)、RUM 或合成探针可提供现场数据,帮助构建贴近实际的负载模型。
基础设施
  • 负载测试在哪里运行? 测试目标应为预发布环境或专用的负载测试环境;未经明确的运维协调,绝不可在生产环境中运行。
  • 预期流量模式是什么? 稳定流量、每日高峰、季节性峰值(黑色星期五)或事件驱动的突发流量——这将决定负载配置。
  • 链路中是否有速率限制、WAF 规则或自动扩缩容? 这些因素会扭曲结果,必须在测试设计中考虑。

核心原则

1. 先测量,再优化

性能直觉并不可靠;开发者经常优化错误的对象。先进行性能分析,找出实际瓶颈,再进行优化。在正确位置经分析确认的 50ms 提升,胜过在错误位置臆测的 500ms 提升。

2. 只有 CI 强制执行预算,预算才真正有效

在 Wiki 中记录、却不在 CI 中检查的预算,几周内就会被打破。将预算接入流水线,设置 k6 阈值和 Lighthouse 断言,让回归导致构建失败,而不是等到季度审查才发现。

3. 贴近实际的负载胜过最大压力

将流量提升到 10 倍的压力测试能告诉你系统的崩溃点。按预期流量的 1.5 倍进行负载测试,则能告诉你明天的真实用户是否会有良好体验。两者都有价值,但贴近实际的负载测试运行频率更高,也能更早发现回归。

4. Core Web Vitals 衡量的是用户的实际感受

服务端指标(延迟、吞吐量)很重要,但用户是在浏览器中体验性能的。LCP、INP 和 CLS 衡量的是感知速度。API 再快,如果渲染很慢,对用户来说依然很慢。

5. 性能是一项功能

性能不会凭空实现。它需要专用的测试基础设施、预算和监控,也需要像保障功能正确性一样持续关注。应以处理功能缺陷同样的紧迫性处理性能回归。

k6 负载测试

k6 是一款开源负载测试工具,使用 JavaScript/TypeScript 编写脚本,可通过 CLI 运行,并可集成到 CI 中。当前稳定版本:k6 v2.0.0(于 2026-05 最终发布)。v2 存在相较于 v1 的破坏性变更——请参阅下方的迁移提示。

负载测试由三个部分构成:负载配置(stages/scenarios 的形态)、检查项(针对每个请求的断言)和阈值(决定通过或失败的预算,并设置退出码)。始终通过 __ENV 设置基础 URL,这样同一脚本就能用于本地、预发布环境和 CI。

完整的基础负载测试、自定义指标和场景示例,请参阅 references/recipes.md。 最简阈值代码块:

export const options = {
  stages: [
    { duration: '1m', target: 20 },
    { duration: '3m', target: 20 },
    { duration: '1m', target: 0 },
  ],
  thresholds: {
    http_req_duration: ['p(95)<500', 'p(99)<1000'],
    http_req_failed: ['rate<0.01'],
  },
};
负载配置
配置要回答的问题形态持续时间
恒定负载系统能否承受正常流量?vus: 50, duration: '10m'10 分钟
逐步加压(压力测试)系统会在什么负载下开始退化?50 → 100 → 200 → 400 → 800 → 012 分钟
突增系统能否从流量突然激增中恢复?50 → 突增至 500 → 持续 → 降至 50 → 恢复6 分钟
长时间稳定负载系统是否会随时间推移发生资源泄漏?增至 100,持续 4 小时,然后逐步降低4 小时以上

只有把“能否恢复?”变成断言,而不是注释,突增测试才算完成。为突增后的时间窗口添加标签(例如 phase:recovery),并针对该窗口设置阈值,这样如果 p95 持续偏高,测试运行就会失败。请参阅 references/recipes.md 中的恢复检测示例。

自定义指标和场景

k6 有四种指标类型:Counter(累计计数)、Rate(非零/真值所占比例,0..1)、Trend(统计分布——p50/p95/p99)、Gauge(最新值)。为请求添加 { tags: { name: 'endpoint' } } 标签,以便按端点、场景或流程筛选指标。

场景可并发运行不同的用户流程,每个场景都有自己的执行器和单独的阈值('http_req_duration{scenario:checkout}': ['p(95)<500'])。可用它们模拟真实的流量组合——同时施加浏览器、结账和以 API 为主的负载。完整的自定义指标和场景示例,请参阅 references/recipes.md。

k6 CI 集成

使用官方 grafana/setup-k6-action@v1 安装 k6,不要手动编写 apt/gpg 密钥服务器代码块(脆弱、容易失效,且无法固定版本)。任何阈值超限时,k6 都会以非零状态码退出,因此无需额外配置,超出预算就会使任务失败。完整的 GitHub Actions 工作流(checkout → setup-k6 → run → upload artifact)请参阅 references/recipes.md。

k6 v1 → v2 迁移(v2.0.0 最终版,2026-05):

  • k6/experimental/websockets → k6/websockets(移除 experimental/ 前缀;现已稳定)
  • k6/experimental/redis → k6/x/redis — 并未移除。导入会自动解析 xk6-redis 扩展(默认启用自动扩展解析;JavaScript 用法不变)。 不要手动编写 Redis 客户端。
  • 已移除 externally-controlled 执行器
  • 已移除 options.ext.loadimpact → 改用 options.cloud(Grafana Cloud k6,原名为 k6 Cloud / Load Impact)
  • CLI:--no-summary → --summary-mode=disabled;--upload-only → k6 cloud upload script.js; 已移除 k6 login/pause/resume/scale/status(改用 k6 cloud login 等);已移除位置参数形式的 k6 cloud script.js
  • 新增退出码 97:由云端中止,且并非阈值导致。请在 CI 处理中加入此情况。 参考:https://grafana.com/docs/k6/latest/get-started/migrating-to-v2/

Web 性能

Lighthouse CI

Lighthouse CI(@lhci/cli)可自动执行 Google Lighthouse 审计,并通过 lighthouserc.js 断言在流水线中强制执行预算。当前版本:@lhci/cli 0.15.x,使用 Lighthouse 12.6 引擎。该项目处于维护模式(距上次发布约一年),且尚不支持 Lighthouse 13(需要 Node 22.19+);它仍是 Lighthouse 的标准 CI 接入方式,但在新项目中采用前请关注上游动态。

完整的 lighthouserc.js(LCP/CLS/TBT/性能评分断言)和 lhci autorun CI 步骤,请参阅 references/recipes.md。

INP 仅能通过现场数据衡量——在实验室中以 TBT 设门槛

这是 Web 性能领域最容易被误解的一点,务必准确理解:

  • INP(Interaction to Next Paint,交互到下一次绘制)是仅能通过现场数据衡量的指标。 Lighthouse 实验室审计加载页面时没有用户交互,因此无法测量或评分 INP。在标准的 lhci autorun 运行中断言 interaction-to-next-paint,等于对 Lighthouse 根本不会生成的指标设门槛。
  • 在实验室中,应以总阻塞时间(TBT)作为代理指标设门槛:断言 'total-blocking-time': ['error', { maxNumericValue: 200 }]。TBT 与 INP 相关,但两者并不相同(页面的 TBT 可能为 0ms,但现场 INP 仍可能不达标)。
  • 从现场数据跟踪真实的 INP——使用 Chrome UX Report(CrUX)或你的 RUM 工具。这才是用户实际体验到的数值,也是 Google 用于排名的指标。
  • 只有在必须测量脚本化交互延迟时,才使用 Lighthouse user-flow / timespan 模式配合脚本化点击,或使用 k6/browser 通过 PerformanceObserver 观察 event 条目。应将其视为脚本化的实验室代理指标,而非现场 INP。

**FID 已退出历史舞台:**FID 已弃用,且 web-vitals v5+ 已移除该指标;INP 于 2024 年 3 月成为 Core Web Vital。不要在任何新代码中对 FID 设断言。

在 Playwright 中测量 CWV

如需在现有 Playwright 测试套件中进行逐页实验室检查,可使用 page.evaluate 和 PerformanceObserver 捕获 LCP 与 CLS(这两个指标在页面加载时都能稳定观测),然后断言 阈值。完整测试见 references/recipes.md。如需在负载下捕获 CWV,请使用同一文件中的 k6/browser 配方。

Core Web Vitals

Google 用于衡量用户感知性能的三项指标。

指标衡量内容良好需要改进较差
LCP(Largest Contentful Paint,最大内容绘制)加载——最大元素的渲染时间≤ 2.5s2.5s–4.0s> 4.0s
INP(Interaction to Next Paint,交互到下一次绘制)响应能力——交互 → 下一次绘制(仅限现场数据)≤ 200ms200ms–500ms> 500ms
CLS(Cumulative Layout Shift,累积布局偏移)视觉稳定性——意外的布局移动≤ 0.10.1–0.25> 0.25

CLS 按面积加权:宽视口上的小型应用如果因迟到的横幅下移 240px,得分也可能只有 0.07。在实验室测试中,还应在首次渲染后固定关键控件的边界框位置 (见 references/recipes.md)。

常见修复方法:

  • LCP——服务器速度慢(使用缓存/CDN、对 LCP 内容进行 SSR/SSG),CSS/JS 阻塞渲染(延迟加载、内联关键 CSS),图片加载慢(使用 WebP/AVIF、对 LCP 图片使用 preload)。
  • INP——JS 长任务(使用 scheduler.yield()、requestIdleCallback),处理器开销大(防抖/节流、使用 Web Workers),布局抖动(通过 requestAnimationFrame 批量读取/写入 DOM)。
  • CLS——为图片设置 width/height,为注入的内容预留空间(使用 aspect-ratio/min-height),使用 font-display: swap 配合 size-adjust,为广告/嵌入内容设置固定尺寸容器。
现场数据与实验室数据
实验室数据现场数据
来源Lighthouse、WebPageTest、Playwright、k6/browserChrome UX Report(CrUX)、RUM 工具
环境模拟环境、受控条件真实用户、真实设备、真实网络
用途调试、CI 门槛、部署前检查了解用户的实际体验
局限性不包含现实世界的差异;没有现场 INP无法复现特定条件

使用实验室数据设置 CI 门槛并进行调试;使用现场数据了解用户的真实体验。若页面的 Lighthouse 得分为 100,但 CrUX 数据不佳,就说明存在实际问题——而 INP 只会出现在现场数据这一栏。

瓶颈识别

超出预算时,按以下顺序排查——切勿猜测,也不要在分析性能之前优化:

  1. 确定缓慢的端点。 k6 中按端点划分的 Trend 指标会给出每个 API 的 p50/p95/p99。最慢的端点是首要排查目标。
  2. 数据库。 检查是否缺少索引(EXPLAIN)、是否存在 N+1 模式(JOIN/批处理)、写入密集型表是否存在锁竞争(优化事务),以及结果集是否不受限制(分页)。
  3. CDN/缓存。 验证静态资源的 cache-control(public, max-age=31536000, immutable)以及 x-cache: HIT 的命中率。
  4. 第三方脚本。 使用 blockedUrlPatterns 屏蔽分析、聊天和跟踪脚本后运行 Lighthouse;对比屏蔽前后的分数,以量化其开销。
  5. 结合服务端指标进行分析。 仅看客户端延迟无法发现原因——检查测试期间的 CPU、内存、磁盘 I/O、连接池饱和度和查询执行时间。

反模式

1. 未协调便对生产环境进行负载测试

负载测试可能触发自动扩缩容(成本高昂)、限流(导致测试失败)、告警(产生不必要的通知)或服务中断。务必与运维团队协调,并将目标设为预发布环境或专用负载测试环境。

2. 负载场景不切实际

产品只有 500 DAU,却测试 10,000 个并发用户;或者实际流量有峰值,却使用均匀流量。根据分析数据建立负载模型;如果没有数据,就从预估峰值的 2 倍开始,逐步增加。

3. 忽略服务端指标

只关注 k6 的客户端响应时间。服务端可能已达到 95% CPU 使用率、连接池已耗尽,或出现内存泄漏。将负载测试结果与服务端指标结合分析。

4. 只在发布前进行性能测试

每季度才进行一次发布前负载测试,会让数十个回归问题不断累积,且难以追溯根因。在 CI 中对每次合并到 main 的更改运行测试,并设置预算以便立即发现回归。

5. 没有性能预算

“LCP 为 3.2s”只是信息;“LCP 必须低于 2.5s”才是门槛。定义预算,并通过 k6 阈值和 Lighthouse 断言强制执行,将超标视为 bug。

6. 在标准 Lighthouse CI 中断言 INP

标准 lhci autorun 实验室模式无法生成 INP 审计结果——因为没有用户交互。在此处设置 interaction-to-next-paint 门槛,相当于对一个 Lighthouse 从未测量的数值设门槛。将 total-blocking-time 设为实验室模式下的代理指标,并通过 CrUX/RUM 跟踪真实 INP。

7. 未经性能分析就进行优化

花几天时间优化一个只占响应时间 2% 的函数。先进行性能分析,找出真正的瓶颈,再进行优化。200ms 的查询每次都比 5ms 的 JS 函数更值得优先处理。

8. 使用空数据库进行测试

生产环境有 1,000 万行数据,却只用 100 行种子数据进行负载测试。数据规模扩大后,查询性能会截然不同。先用生产规模的(匿名化)数据填充负载测试环境。

验证

在声称完成之前,证明这些产物确实有效:

  • k6 脚本: k6 run --summary-mode=disabled load-tests/api-load.js 以 0 退出,且测试结束摘要中每一行 thresholds 都显示绿色(✓)。红色阈值行表示预算超标,且退出码非零。
  • 尖峰恢复: 运行尖峰脚本,并确认摘要中出现 {phase:recovery} 阈值且测试通过——这证明恢复过程经过了断言,而不只是写在注释里。
  • Lighthouse CI: lhci autorun 以 0 退出,且所有 ['error', ...] 断言均通过;LCP/CLS/TBT 断言超标时,退出码为非零。

完成标准

  • k6 脚本涵盖目标负载配置:基线(恒定负载)、压力(逐步升至崩溃点)和持久负载,每个脚本都通过 __ENV 指定基础 URL。
  • 峰值测试通过限定在峰值后时间窗口内的阈值断言恢复情况(例如 http_req_duration{phase:recovery}),而不只是添加 // recovery 注释。
  • 将性能预算编码为 k6 阈值(例如 p(95)<500、http_req_failed rate<0.01),超出预算时使 CI 任务失败。
  • Lighthouse CI 的 lighthouserc.js 通过 ['error', ...] 断言,对 largest-contentful-paint、cumulative-layout-shift 和 total-blocking-time(INP 的实验室环境代理指标)进行合并门禁;真实 INP 通过 CrUX/RUM 跟踪,而非在实验室环境中断言。
  • 为每个关键页面(首页、结账页、仪表板)记录 Core Web Vitals 基线,并标注 Good/Needs Improvement/Poor 分类。
  • 测试结果包含每种场景的 p95 和 p99 延迟、错误率及吞吐量,并作为 CI 构建产物保存。

参考文件(位于 references/ 中)

  • recipes.md — 可运行的示例:基础 k6 负载测试、带恢复检测的峰值测试、自定义指标、场景、k6 CI 工作流(grafana/setup-k6-action)、lighthouserc.js、k6/browser 在负载下测试 CWV 的示例,以及 Playwright LCP/CLS 测试。

相关技能

  • ci-cd-integration — 配置 k6 和 Lighthouse CI 的流水线、安排每晚运行,并通过预算控制部署。
  • qa-metrics — 将 LCP/INP/CLS 和 p95 延迟纳入更全面的 QA 指标仪表板。
  • release-readiness — 在发布与否检查清单中纳入性能基准。
  • synthetic-monitoring — 发布后安排生产环境 CWV/正常运行时间探测;此技能用于发布前的实验室环境门禁。
  • observability-driven-testing — 在生产遥测数据作为设计新性能测试的输入时使用。
  • qa-project-context — 记录性能预算、流量模式和待测试的关键流程。

评论

支持 Markdown