performance-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<objective>
Measure, assert, and protect application performance with budgets enforced in CI, not
subjective "feels fast enough" assessments. This skill covers two domains: **load testing**
(can the backend handle traffic?) and **web performance** (is the frontend fast for users?).
A report that says "LCP is 3.2s" is information; a CI gate that fails the build at 2.5s is
accountability.
</objective>
<objective>
通过在CI中强制执行预算来衡量、验证并保障应用性能,而非依赖主观的“感觉足够快”评估。本技能涵盖两大领域:**负载测试**(后端能否承受流量?)和**Web性能**(前端对用户而言是否快速?)。一份显示“LCP为3.2秒”的报告只是信息;而当LCP超过2.5秒时就会失败的CI门禁才是问责机制。
</objective>
Quick Route
快速指引
| You need to... | Go to |
|---|---|
| Test backend capacity / throughput / latency under traffic | k6 Load Testing → |
| Pick a load shape (constant / ramp / spike / soak) | Load Profiles table |
| Measure frontend speed for real users (LCP, INP, CLS) | Web Performance + Core Web Vitals |
| Gate page perf in CI | Lighthouse CI (gate TBT, not INP — see below) |
| A budget is breached and you must find why | Bottleneck Identification |
| Migrate an existing suite from k6 v1 → v2 | k6 v2 Migration callout |
| 你需要... | 前往 |
|---|---|
| 测试流量下后端的容量/吞吐量/延迟 | k6负载测试 → |
| 选择负载模式(恒定/渐变/峰值/浸泡) | 负载配置文件表格 |
| 衡量真实用户的前端速度(LCP、INP、CLS) | Web性能 + Core Web Vitals |
| 在CI中管控页面性能 | Lighthouse CI(管控TBT,而非INP——见下文) |
| 预算已被突破,需查找原因 | 瓶颈识别 |
| 将现有测试套件从k6 v1迁移至v2 | k6 v2迁移提示 |
Discovery Questions
调研问题
Check first — if it exists, use it and skip questions
already answered there.
.agents/qa-project-context.md首先查看——若存在,使用其中内容并跳过已回答的问题。
.agents/qa-project-context.mdWhat to Measure
测量对象
- Web performance or load testing? Web performance measures user-perceived speed (Core Web Vitals, page load). Load testing measures server capacity (RPS, latency under load). Most products need both.
- Which user journeys are performance-critical? Not every endpoint needs load testing. Focus on high-traffic, revenue-critical, or latency-sensitive flows.
- Existing performance budgets? If yes, what are the targets? If no, this skill helps establish them — measure baseline first.
- Web性能测试还是负载测试? Web性能测试衡量用户感知的速度(Core Web Vitals、页面加载)。负载测试衡量服务器容量(RPS、负载下的延迟)。大多数产品两者都需要。
- 哪些用户旅程对性能至关重要?并非每个端点都需要负载测试。重点关注高流量、影响营收或对延迟敏感的流程。
- 是否已有性能预算?如果有,目标是什么?如果没有,本技能可帮助建立预算——先测量基准值。
Current State
当前状态
- What is the current baseline? You need numbers before you can set targets. Measure first, then define budgets.
- What broke due to performance before? Slow pages that lost users, endpoints that timed out under load, queries that locked up — these point at where to focus.
- Existing monitoring? APM (Datadog, New Relic), RUM, or synthetic probes give you field data to model realistic load.
- 当前基准值是多少?在设定目标前你需要有数据。先测量,再定义预算。
- 之前因性能问题出过哪些故障?导致用户流失的慢页面、负载下超时的端点、锁死的查询——这些指出了需要关注的重点。
- 是否已有监控?APM(Datadog、New Relic)、RUM或合成探测工具可为你提供真实负载建模的现场数据。
Infrastructure
基础设施
- Where does load testing run? Target staging or a dedicated load-test environment, never production without explicit operations coordination.
- Expected traffic pattern? Steady, daily peaks, seasonal spikes (Black Friday), or event-driven bursts — this picks the load profile.
- Rate limits, WAF rules, or auto-scaling in the path? These distort results and must be accounted for in test design.
- 负载测试在哪里运行?目标环境为预发布环境或专用负载测试环境,未经运维明确协调绝不能在生产环境运行。
- 预期流量模式是什么?稳定流量、每日峰值、季节性峰值(如黑色星期五)或事件驱动的突发流量——这决定了负载配置文件的选择。
- 路径中是否有速率限制、WAF规则或自动扩缩容?这些会扭曲测试结果,必须在测试设计中加以考虑。
Core Principles
核心原则
1. Measure before optimizing
1. 先测量再优化
Performance intuition is unreliable; developers routinely optimize the wrong thing. Profile first, identify the actual bottleneck, then optimize. A profiled 50ms win in the right place beats an assumed 500ms win in the wrong one.
性能直觉不可靠;开发人员经常优化错误的点。先分析性能,识别实际瓶颈,再进行优化。在正确的地方获得50毫秒的提升,远胜于在错误的地方臆想500毫秒的优化效果。
2. Budgets are only real if CI enforces them
2. 只有被CI强制执行的预算才是真实有效的
A budget documented in a wiki but not checked in CI is violated within weeks. Wire budgets into the pipeline as k6 thresholds and Lighthouse assertions so regressions fail the build, not a quarterly review.
记录在维基文档中但未在CI中检查的预算,几周内就会被违反。将预算作为k6阈值和Lighthouse断言集成到流水线中,这样性能回归会直接导致构建失败,而非等到季度评审才发现。
3. Realistic load beats maximum stress
3. 真实负载优于极限压力测试
A stress test to 10x traffic tells you the breaking point. A load test at 1.5x expected traffic tells you whether tomorrow's real users have a good experience. Both have value, but realistic load runs more often and catches regressions earlier.
将流量提升至10倍的压力测试能告诉你系统的崩溃点。而基于预期流量1.5倍的负载测试,能告诉你明天的真实用户是否有良好体验。两者都有价值,但真实负载测试更常运行,能更早发现回归问题。
4. Core Web Vitals are what users actually feel
4. Core Web Vitals是用户实际感知到的性能
Server-side metrics (latency, throughput) matter, but users experience performance through the browser. LCP, INP, and CLS measure perceived speed. A fast API that renders slowly is still slow to users.
服务器端指标(延迟、吞吐量)很重要,但用户是通过浏览器体验性能的。LCP、INP和CLS衡量的是感知速度。一个快速的API如果渲染缓慢,对用户来说仍然是慢的。
5. Performance is a feature
5. 性能是一项功能
It does not happen by accident. It needs dedicated test infrastructure, budgets, and monitoring, and the same continuous attention as functional correctness. Treat a performance regression with the same urgency as a functional bug.
它不会偶然出现。它需要专用的测试基础设施、预算和监控,以及与功能正确性同等持续的关注。对待性能回归要像对待功能bug一样紧急。
k6 Load Testing
k6负载测试
k6 is an open-source load testing tool that uses JavaScript/TypeScript for scripts, runs
from the CLI, and integrates with CI. Current stable: k6 v2.0.0 (final shipped
2026-05). v2 has breaking changes from v1 — see the migration callout below.
A load test is built from three pieces: a load profile (the /
shape), checks (per-request assertions), and thresholds (pass/fail budgets that
set the exit code). Always drive the base URL from so the same script runs against
local, staging, and CI.
stagesscenarios__ENVSee for the full basic load test, custom metrics, and scenarios.
A minimal threshold block:
references/recipes.mdjavascript
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'],
},
};k6是一款开源负载测试工具,使用JavaScript/TypeScript编写脚本,通过CLI运行,并可与CI集成。当前稳定版本:k6 v2.0.0(最终发布于2026年5月)。v2相较于v1有破坏性变更——见下文的迁移提示。
负载测试由三部分构成:负载配置文件(/的模式)、检查项(每个请求的断言)和阈值(决定退出码的通过/失败预算)。始终从获取基准URL,以便同一脚本可在本地、预发布和CI环境中运行。
stagesscenarios__ENV完整的基础负载测试、自定义指标和场景示例请参见。一个最小化阈值块示例:
references/recipes.mdjavascript
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'],
},
};Load Profiles
负载配置文件
| Profile | Question | Shape | Duration |
|---|---|---|---|
| Constant | Can the system handle normal traffic? | | 10 min |
| Ramp-up (stress) | At what point does it degrade? | 50 → 100 → 200 → 400 → 800 → 0 | 12 min |
| Spike | Does it recover from a sudden surge? | 50 → spike 500 → sustain → drop 50 → recover | 6 min |
| Soak | Does it leak resources over time? | Ramp to 100, sustain 4h, ramp down | 4+ hours |
A spike test is not done until "does it recover?" is an assertion, not a comment. Tag
the post-spike window (e.g. ) and scope a threshold to it so the run fails
if p95 stays elevated. See the recovery-detection recipe in .
phase:recoveryreferences/recipes.md| 配置文件 | 适用问题 | 模式 | 时长 |
|---|---|---|---|
| 恒定负载 | 系统能否处理正常流量? | | 10分钟 |
| 渐变上升(压力测试) | 系统在什么点开始性能下降? | 50 → 100 → 200 → 400 → 800 → 0 | 12分钟 |
| 峰值测试 | 系统能否从突发流量中恢复? | 50 → 峰值500 → 持续 → 降至50 → 恢复 | 6分钟 |
| 浸泡测试 | 系统是否会随时间泄漏资源? | 渐变至100,持续4小时,再渐变下降 | 4小时以上 |
峰值测试必须将“能否恢复”作为断言,而非注释。标记峰值后的阶段(如)并为该阶段设置阈值,若p95延迟仍居高不下则测试失败。请参见中的恢复检测示例。
phase:recoveryreferences/recipes.mdCustom Metrics and Scenarios
自定义指标与场景
k6 has four metric types: (cumulative count), (proportion of non-zero/true
values, 0..1), (statistical distribution — p50/p95/p99), (latest value). Tag
requests with to filter metrics per endpoint, scenario, or
flow.
CounterRateTrendGauge{ tags: { name: 'endpoint' } }Scenarios run distinct user flows concurrently, each with its own executor and
per-scenario thresholds (). Use them
to model a real mix — browsers + checkout + API-heavy load at once. Full custom-metric and
scenario examples are in .
'http_req_duration{scenario:checkout}': ['p(95)<500']references/recipes.mdk6有四种指标类型:(累计计数)、(非零/真值的比例,0到1)、(统计分布——p50/p95/p99)、(最新值)。使用标记请求,以便按端点、场景或流程过滤指标。
CounterRateTrendGauge{ tags: { name: 'endpoint' } }场景可同时运行不同的用户流程,每个流程有自己的执行器和场景专属阈值(如)。使用场景可模拟真实流量组合——浏览器流量+结账流程+API密集型负载同时运行。完整的自定义指标和场景示例请参见。
'http_req_duration{scenario:checkout}': ['p(95)<500']references/recipes.mdk6 CI Integration
k6 CI集成
Install k6 with the official — not a hand-rolled apt/gpg
keyserver block (brittle, rots, no version pin). k6 exits non-zero when any threshold is
breached, so a breached budget fails the job with no extra wiring. The full GitHub Actions
workflow (checkout → setup-k6 → run → upload artifact) is in .
grafana/setup-k6-action@v1references/recipes.mdk6 v1 → v2 migration (v2.0.0 final, 2026-05):
→k6/experimental/websockets(drop thek6/websocketsprefix; stable now)experimental/ →k6/experimental/redis— NOT removed. The import auto-resolves thek6/x/redisextension (auto-extension-resolution is on by default; JS usage unchanged). Do not hand-roll a Redis client.xk6-redis executor removedexternally-controlled removed → useoptions.ext.loadimpact(Grafana Cloud k6, formerly k6 Cloud / Load Impact)options.cloud- CLI:
→--no-summary;--summary-mode=disabled→--upload-only;k6 cloud upload script.js/k6 login/pause/resume/scaleremoved (usestatus, etc.); positionalk6 cloud loginremovedk6 cloud script.js- Exit code 97 is new: a non-threshold cloud-side abort. Wire it into CI handling. Reference: https://grafana.com/docs/k6/latest/get-started/migrating-to-v2/
使用官方的****安装k6——不要手动编写apt/gpg密钥服务器代码块(脆弱、易失效、无法固定版本)。当任何阈值被突破时,k6会返回非零退出码,因此预算被突破会直接导致任务失败,无需额外配置。完整的GitHub Actions工作流(检出代码→安装k6→运行测试→上传产物)请参见。
grafana/setup-k6-action@v1references/recipes.mdk6 v1 → v2迁移(v2.0.0最终版,2026年5月):
→k6/experimental/websockets(移除k6/websockets前缀;现已稳定)experimental/ →k6/experimental/redis——未被移除。该导入会自动解析k6/x/redis扩展(自动扩展解析默认开启;JS用法不变)。请勿手动编写Redis客户端。xk6-redis- 移除
执行器externally-controlled- 移除
→ 使用options.ext.loadimpact(Grafana Cloud k6,前身为k6 Cloud / Load Impact)options.cloud- 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 Performance
Web性能
Lighthouse CI
Lighthouse CI
Lighthouse CI () automates Google Lighthouse audits and enforces budgets in the
pipeline via assertions. Current: 0.15.x on the Lighthouse 12.6
engine. The project is in maintenance mode (last release ~a year ago) and does not yet
support Lighthouse 13 (needs Node 22.19+); it remains the standard CI surface for Lighthouse,
but watch upstream before adopting in greenfield projects.
@lhci/clilighthouserc.js@lhci/cliThe full (LCP/CLS/TBT/perf-score assertions) and the CI
step are in .
lighthouserc.jslhci autorunreferences/recipes.mdLighthouse CI()可自动执行Google Lighthouse审计,并通过中的断言在流水线中强制执行预算。当前版本:基于Lighthouse 12.6引擎的 0.15.x。该项目处于维护模式(上次发布约一年前),尚不支持Lighthouse 13(需要Node 22.19+);它仍是Lighthouse的标准CI集成方案,但在新项目中采用前需关注上游动态。
@lhci/clilighthouserc.js@lhci/cli完整的(包含LCP/CLS/TBT/性能得分断言)和 CI步骤示例请参见。
lighthouserc.jslhci autorunreferences/recipes.mdINP is field-only — gate TBT in the lab
INP仅适用于现场数据——在实验室环境中管控TBT
This is the single most-misunderstood point in web perf, so be precise:
- INP (Interaction to Next Paint) is a field-only metric. A Lighthouse lab audit loads
a page with no user interaction, so it cannot measure or score INP. Asserting
in a standard
interaction-to-next-paintrun gates something Lighthouse never produces.lhci autorun - In the lab, gate Total Blocking Time (TBT) as the proxy: assert
. TBT correlates with INP but is not identical (a page can hit 0ms TBT and still fail field INP).
'total-blocking-time': ['error', { maxNumericValue: 200 }] - Track real INP from the field — Chrome UX Report (CrUX) or your RUM tool. That is the number users actually experience and the one Google ranks on.
- Only if you must measure scripted-interaction latency, use Lighthouse user-flow /
timespan mode with scripted clicks, or with a
k6/browseronPerformanceObserverentries. Treat that as a scripted lab proxy, still not field INP.event
FID is gone: FID was deprecated andv5+ removed it; INP became a Core Web Vital in March 2024. Do not assert on FID in any new code.web-vitals
这是Web性能领域最容易被误解的点,请务必明确:
- INP(Interaction to Next Paint,交互到下一次绘制)是仅适用于现场的指标。 Lighthouse实验室审计加载页面时无用户交互,因此无法测量或评分INP。在标准运行中断言
lhci autorun,实际上是在管控一个Lighthouse从未生成过的数值。interaction-to-next-paint - 在实验室环境中,管控Total Blocking Time(TBT,总阻塞时间)作为替代指标:断言。TBT与INP相关但并不完全相同(页面可能TBT为0毫秒但现场INP不达标)。
'total-blocking-time': ['error', { maxNumericValue: 200 }] - 从现场数据跟踪真实INP——使用Chrome UX Report(CrUX)或你的RUM工具。这才是用户实际体验到的数值,也是Google排名所依据的指标。
- 若必须测量脚本化交互延迟,请使用Lighthouse用户流程/时间段模式配合脚本化点击,或使用并通过
k6/browser监听PerformanceObserver条目。这仅作为脚本化实验室替代方案,仍不是现场INP。event
FID已被移除: FID已被弃用,v5+版本已移除该指标;INP于2024年3月成为Core Web Vital。请勿在任何新代码中断言FID。web-vitals
Measuring CWV in Playwright
在Playwright中测量CWV
For a per-page lab check inside your existing Playwright suite, use with a
to capture LCP and CLS (both observe cleanly on page load), then assert
the thresholds. Full test in . For under-load CWV capture, use the
recipe in the same file.
page.evaluatePerformanceObserverreferences/recipes.mdk6/browser若要在现有Playwright套件中对单个页面进行实验室检查,可使用配合捕获LCP和CLS(两者均可在页面加载时清晰观测),然后断言阈值。完整测试示例请参见。若要在负载下捕获CWV,请使用同一文档中的示例。
page.evaluatePerformanceObserverreferences/recipes.mdk6/browserCore Web Vitals
Core Web Vitals
The three metrics Google uses for user-perceived performance.
| Metric | Measures | Good | Needs Improvement | Poor |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | Loading — when the largest element renders | ≤ 2.5s | 2.5s–4.0s | > 4.0s |
| INP (Interaction to Next Paint) | Responsiveness — interaction → next paint (field-only) | ≤ 200ms | 200ms–500ms | > 500ms |
| CLS (Cumulative Layout Shift) | Visual stability — unexpected layout movement | ≤ 0.1 | 0.1–0.25 | > 0.25 |
Common fixes:
- LCP — slow server (cache/CDN, SSR/SSG the LCP content), render-blocking CSS/JS (defer, inline critical CSS), slow image load (WebP/AVIF, the LCP image).
preload - INP — long JS tasks (,
scheduler.yield()), heavy handlers (debounce/throttle, Web Workers), layout thrashing (batch DOM reads/writes viarequestIdleCallback).requestAnimationFrame - CLS — set /
widthon images, reserve space for injected content (height/aspect-ratio),min-heightwithfont-display: swap, fixed-size containers for ads/embeds.size-adjust
Google用于衡量用户感知性能的三项指标。
| 指标 | 衡量内容 | 良好 | 需要改进 | 较差 |
|---|---|---|---|---|
| LCP(Largest Contentful Paint,最大内容绘制) | 加载性能——最大元素完成渲染的时间 | ≤ 2.5秒 | 2.5秒–4.0秒 | > 4.0秒 |
| INP(Interaction to Next Paint,交互到下一次绘制) | 响应性能——交互到下一次绘制的时间(仅适用于现场) | ≤ 200毫秒 | 200毫秒–500毫秒 | > 500毫秒 |
| CLS(Cumulative Layout Shift,累积布局偏移) | 视觉稳定性——意外的布局移动 | ≤ 0.1 | 0.1–0.25 | > 0.25 |
常见修复方案:
- LCP ——优化慢服务器(缓存/CDN、对LCP内容使用SSR/SSG)、减少阻塞渲染的CSS/JS(延迟加载、内联关键CSS)、优化慢图片加载(使用WebP/AVIF格式、LCP图片)。
preload - INP ——拆分长JS任务(使用、
scheduler.yield())、优化重型处理函数(防抖/节流、使用Web Workers)、避免布局抖动(通过requestIdleCallback批量DOM读写)。requestAnimationFrame - CLS ——为图片设置/
width、为注入内容预留空间(使用height/aspect-ratio)、使用min-height配合font-display: swap、为广告/嵌入内容使用固定尺寸容器。size-adjust
Field vs. Lab Data
现场数据 vs 实验室数据
| Lab Data | Field Data | |
|---|---|---|
| Source | Lighthouse, WebPageTest, Playwright, k6/browser | Chrome UX Report (CrUX), RUM tools |
| Environment | Simulated, controlled | Real users, real devices, real networks |
| Use for | Debugging, CI gates, pre-deployment | Understanding actual user experience |
| Limitation | No real-world variance; no field INP | Cannot reproduce specific conditions |
Use lab data for CI gates and debugging; use field data to understand the real user
experience. A page that scores 100 in Lighthouse but has poor CrUX data has a real problem —
and INP only ever shows up in the field column.
| 实验室数据 | 现场数据 | |
|---|---|---|
| 来源 | Lighthouse、WebPageTest、Playwright、k6/browser | Chrome UX Report(CrUX)、RUM工具 |
| 环境 | 模拟、受控 | 真实用户、真实设备、真实网络 |
| 用途 | 调试、CI门禁、预部署检查 | 了解实际用户体验 |
| 局限性 | 无真实环境差异;无法获取现场INP | 无法重现特定场景 |
使用实验室数据进行CI门禁和调试;使用现场数据了解真实用户体验。一个在Lighthouse中得分为100但CrUX数据较差的页面,确实存在真实问题——而且INP只会出现在现场数据中。
Bottleneck Identification
瓶颈识别
When a budget is breached, investigate in this order — never guess, never optimize before
profiling:
- Identify the slow endpoint. Per-endpoint metrics in k6 give p50/p95/p99 per API. The slowest is the first target.
Trend - Database. Check missing indexes (), N+1 patterns (JOIN/batch), lock contention on write-heavy tables (optimize transactions), unbounded result sets (paginate).
EXPLAIN - CDN/caching. Verify on static assets (
cache-control) and thepublic, max-age=31536000, immutablerate.x-cache: HIT - Third-party scripts. Run Lighthouse with for analytics/chat/tracking; compare scores with and without to quantify the cost.
blockedUrlPatterns - Correlate with server metrics. Client-side latency alone hides the cause — check CPU, memory, disk I/O, connection-pool saturation, and query execution time during the run.
当预算被突破时,按以下顺序排查——绝不猜测,绝不在分析性能前进行优化:
- 识别慢端点。 k6中的端点级指标可提供每个API的p50/p95/p99延迟。最慢的端点是首要排查目标。
Trend - 数据库。 检查缺失的索引(使用)、N+1查询模式(使用JOIN/批量查询)、写密集型表的锁竞争(优化事务)、无限制结果集(分页)。
EXPLAIN - CDN/缓存。 验证静态资源的设置(
cache-control)和public, max-age=31536000, immutable命中率。x-cache: HIT - 第三方脚本。 使用在Lighthouse中屏蔽分析/聊天/跟踪脚本;对比屏蔽前后的得分,量化其性能影响。
blockedUrlPatterns - 关联服务器指标。 仅看客户端延迟无法找到根本原因——检查测试运行期间的CPU、内存、磁盘I/O、连接池饱和度和查询执行时间。
Anti-Patterns
反模式
1. Load testing production without coordination
1. 未经协调在生产环境运行负载测试
Load tests can trigger auto-scaling (expensive), rate limiting (test fails), alerts (unnecessary pages), or outages. Always coordinate with operations and target staging or a dedicated load-test environment.
负载测试可能触发自动扩缩容(成本高昂)、速率限制(测试失败)、告警(不必要的通知)或服务中断。务必与运维协调,目标环境为预发布或专用负载测试环境。
2. Unrealistic load scenarios
2. 不切实际的负载场景
Testing 10,000 concurrent users when the product has 500 DAU, or uniform traffic when real traffic has peaks. Model load from analytics; absent that, start at 2x estimated peak and increase.
当产品日活用户仅500时,测试10000并发用户;或当真实流量存在峰值时,使用均匀流量测试。根据分析数据建模负载;若无分析数据,从预估峰值的2倍开始测试并逐步增加。
3. Ignoring server-side metrics
3. 忽略服务器端指标
Looking only at k6's client-side response times. The server may be at 95% CPU, the connection pool exhausted, or memory leaking. Correlate load results with server metrics.
仅关注k6的客户端响应时间。服务器可能处于95% CPU使用率、连接池耗尽或内存泄漏状态。需将负载测试结果与服务器指标关联分析。
4. Performance testing only before releases
4. 仅在发布前进行性能测试
A quarterly pre-release load test lets dozens of regressions accumulate with untraceable root causes. Run in CI on every merge to main with budgets that catch regressions immediately.
每季度一次的发布前负载测试会让大量回归问题累积,且无法追踪根本原因。应在每次合并到主分支时都在CI中运行性能测试,通过预算及时发现回归问题。
5. No performance budgets
5. 无性能预算
"LCP is 3.2s" is information; "LCP must be under 2.5s" is a gate. Define budgets, enforce them as k6 thresholds and Lighthouse assertions, and treat violations as bugs.
“LCP为3.2秒”只是信息;“LCP必须低于2.5秒”才是门禁。定义预算,将其作为k6阈值和Lighthouse断言强制执行,并将预算违反视为bug处理。
6. Asserting INP in standard Lighthouse CI
6. 在标准Lighthouse CI中断言INP
Standard lab mode cannot produce an INP audit — no user interaction. Gating there gates a number Lighthouse never measures. Gate as the lab proxy and track real INP from CrUX/RUM.
lhci autoruninteraction-to-next-painttotal-blocking-time标准实验室模式无法生成INP审计结果——无用户交互。在此处管控,实际上是在管控一个Lighthouse从未测量过的数值。应管控作为实验室替代指标,并从CrUX/RUM跟踪真实INP。
lhci autoruninteraction-to-next-painttotal-blocking-time7. Optimizing without profiling
7. 未分析性能就进行优化
Spending days on a function that is 2% of response time. Profile, find the actual bottleneck, then optimize. The 200ms query beats the 5ms JS function every time.
花费数天优化一个仅占响应时间2%的函数。先分析性能,找到实际瓶颈,再进行优化。200毫秒的查询优化远胜于5毫秒的JS函数优化。
8. Testing with empty databases
8. 使用空数据库进行测试
Load testing against 100 seeded rows when production has 10 million. Query performance is radically different at scale. Seed the load-test environment with production-scale (anonymized) data first.
当生产环境有1000万条数据时,仅用100条种子数据进行负载测试。查询性能在不同数据规模下差异极大。负载测试环境需先导入与生产规模相当的(匿名化)数据。
Verification
验证
Prove the artifacts actually work before claiming done:
- k6 script: exits 0 and the end-of-test summary shows every
k6 run --summary-mode=disabled load-tests/api-load.jsline green (thresholds). A red threshold line means a breached budget and a non-zero exit.✓ - Spike recovery: run the spike script and confirm the threshold appears in the summary and passes — proving recovery is asserted, not just commented.
{phase:recovery} - Lighthouse CI: exits 0 with all
lhci autorunassertions passing; a breached LCP/CLS/TBT assertion exits non-zero.['error', ...]
在完成前需证明产物确实有效:
- k6脚本: 返回0,且测试结束摘要显示所有
k6 run --summary-mode=disabled load-tests/api-load.js行均为绿色(thresholds)。红色阈值行表示预算被突破,返回非零退出码。✓ - 峰值恢复: 运行峰值测试脚本,确认阈值出现在摘要中并通过——证明恢复已被断言,而非仅注释。
{phase:recovery} - Lighthouse CI: 返回0,所有
lhci autorun断言均通过;若LCP/CLS/TBT断言被突破,则返回非零退出码。['error', ...]
Done When
完成标准
- k6 scripts cover the target load profiles: baseline (constant), stress (ramp to breaking point), and soak (sustained), each with -driven base URL.
__ENV - Spike test asserts recovery via a threshold scoped to the post-spike window (e.g. ), not just a
http_req_duration{phase:recovery}comment.// recovery - Performance budgets encoded as k6 thresholds (e.g. ,
p(95)<500) that fail the CI job when exceeded.http_req_failed rate<0.01 - Lighthouse CI gates merges on
lighthouserc.js,largest-contentful-paint, andcumulative-layout-shift(the lab proxy for INP) astotal-blocking-timeassertions; real INP tracked from CrUX/RUM, not asserted in lab.['error', ...] - Core Web Vitals baselines documented for each key page (home, checkout, dashboard) with Good/Needs Improvement/Poor classification.
- Test results include p95 and p99 latency, error rate, and throughput per scenario, stored as CI artifacts.
- k6脚本覆盖目标负载配置文件:基准(恒定)、压力(渐变至崩溃点)和浸泡(持续),且均使用驱动的基准URL。
__ENV - 峰值测试通过针对峰值后阶段的阈值(如)断言恢复能力,而非仅添加
http_req_duration{phase:recovery}注释。// recovery - 性能预算被编码为k6阈值(如、
p(95)<500),当预算被突破时CI任务失败。http_req_failed rate<0.01 - Lighthouse CI的将
lighthouserc.js、largest-contentful-paint和cumulative-layout-shift(INP的实验室替代指标)作为total-blocking-time断言管控合并操作;真实INP从CrUX/RUM跟踪,不在实验室中断言。['error', ...] - 已记录每个关键页面(首页、结账页、仪表盘)的Core Web Vitals基准值,并进行了良好/需要改进/较差的分类。
- 测试结果包含每个场景的p95和p99延迟、错误率及吞吐量,并作为CI产物存储。
Reference Files (in references/
)
references/参考文件(位于references/
目录)
references/- recipes.md — runnable artifacts: basic k6 load test, spike-with-recovery detection, custom metrics, scenarios, k6 CI workflow (),
grafana/setup-k6-action, thelighthouserc.jsCWV-under-load example, and the Playwright LCP/CLS test.k6/browser
- recipes.md ——可运行的产物示例:基础k6负载测试、带恢复检测的峰值测试、自定义指标、场景、k6 CI工作流()、
grafana/setup-k6-action、负载下CWV测量的lighthouserc.js示例,以及Playwright LCP/CLS测试。k6/browser
Related Skills
相关技能
- ci-cd-integration — pipeline wiring for k6 and Lighthouse CI, scheduling nightly runs, gating deployments on budgets.
- qa-metrics — LCP/INP/CLS and p95 latency as part of the broader QA metrics dashboard.
- release-readiness — performance benchmarks in the go/no-go checklist.
- synthetic-monitoring — scheduled production CWV/uptime probes after release; this skill is pre-release lab gating.
- observability-driven-testing — when prod telemetry is the input to designing new perf tests.
- qa-project-context — captures performance budgets, traffic patterns, and critical flows to test.
- ci-cd-integration ——k6和Lighthouse CI的流水线配置、夜间测试调度、基于预算管控部署。
- qa-metrics ——将LCP/INP/CLS和p95延迟纳入更广泛的QA指标仪表盘。
- release-readiness ——将性能基准纳入发布准入 checklist。
- synthetic-monitoring ——发布后对生产环境进行定期CWV/可用性探测;本技能针对预发布阶段的实验室管控。
- observability-driven-testing ——当生产遥测作为设计新性能测试的输入时使用。
- qa-project-context ——记录性能预算、流量模式及需测试的关键流程。