后端与接口
当需要检查 Grafana Cloud k6…
对 Grafana Cloud k6 同一 load test 的多次运行做趋势分析,识别性能退化、计算阈值余量并给出收紧阈值建议。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
当需要检查 Grafana Cloud 特定
解决思路
- 执行任何 GCk6 API 调用前先阅读 k6-manage,复用其认证、路径构造(双层 cloud/cloud/ 前缀)、@nextLink 分页、spill envelope 和 metric query 语法;不要在本技能中重复这些知识。
- 使用工具 gcx(按 k6-manage 的模式调用)。
- 按顺序执行 Workflow;最后只呈现发现,不要直接应用任何变更。
- Step 1:让用户提供 GCk6 URL、test ID 或 test name;若给 URL,从路径中提取 load test ID。
- Step 1:若用户给 test name,用 gcx k6 tests list 或 v6 API 搜索。
- Step 1:获取 test metadata 确认存在,记录 id、name、project_id、created 时间戳;后续多 run 指标端点需要 load test ID,而不是 run ID。
- Step 2:默认分析窗口为过去 30 天。
- Step 2:若用户指定窗口则调整;若 30 天内 run 很少(<5)则扩大窗口并说明;若 run 极多(30 天数百次)考虑抽样或缩小,若 >200 个 run 询问用户。
- Step 2:明确声明分析窗口:Analyzing runs from {start_date} to {end_date}。
- Step 3:用 v6 API 和 $orderby=created desc 分页列出该 test 的所有 run(分页循环见 k6-manage Section 3 的 @nextLink 模式),并过滤到分析窗口内。
- Step 3:对每个 run 记录 id、created、ended、result(passed/failed/timed_out)、status(created/queued/initializing/running/finished/aborted)、note(如有)。
- Step 3:默认丢弃未达到 finished 状态的 run(aborted、timed_out 等),除非用户明确要求分析它们;不完整 run 会产生不可靠的指标聚合。
- Step 3:计数可用 run;若少于 3 个,告知用户样本量不足以做趋势分析,建议扩大窗口或等待更多 run。
- Step 4:查询值之前先发现 test 发出的 metrics;使用 multi-run metric listing endpoint:GET /cloud/v5/load_tests/{loadTestId}/metrics(test_run_ids=[{id1},{id2},...])。
- Step 4:传入代表性 run ID 子集(最早和最新的几个 run),以捕获窗口内新增或移除的 metrics。
- Step 4:记录每个 metric 的 name 和 type(counter、gauge、trend、rate)。
- Step 4:按 type 分组;查询方法必须匹配 metric type,否则返回空结果(见 metrics.md Query methods)。
- Step 5:对每个 metric,用 multi-run aggregate endpoint 查询其在窗口内所有 run 的聚合值:GET /cloud/v5/load_tests/{loadTestId}/query_aggregate_k6(query='<method>', metric='<metric_name>', test_run_ids=[{id1},{id2},...])。
- Step 5:具体 gcx 形式(代理前缀按 k6-manage §2;-o json 避免 spill envelope):LT=<load_test_id>; IDS="123,124,125"; gcx --context <ctx> api "/api/plugins/k6-app/resources/cloud/cloud/v5/load_tests/$LT/query_aggregate_k6(query='histogram_quantile(0.95)',metric='http_req_duration',test_run_ids=[$IDS])" -o json
- Step 5:按 metric type 选择聚合方法:trend -> histogram_quantile(0.95) 捕获 P95 latency(最常见 SLO 目标);trend -> histogram_quantile(0.5) 捕获中位数;trend -> histogram_avg 捕获均值(对离群值敏感);counter -> increase 捕获每 run 总数;rate -> ratio 捕获成功/失败比例;gauge -> max 捕获每 run 峰值。
- Step 5:对 trend 类型 metrics(延迟)查询多个分位数(P50、P90、P95、P99),判断退化是均匀还是集中在尾部。
- Step 5:对多目标 test 一定要按 request grouping 拆分;单个 test 级 aggregate p95 会掩盖只发生在某 endpoint 或某 page 的退化,一个 URL 3 倍变慢可能在 test 级 p95 中不可见。
- Step 5:默认分组:browser_web_vital_*(LCP、FCP、CLS、TTFB、INP、FID)按 by (url),因为每次导航发出自己的 web vital,按 URL 趋势可定位到具体页面。
- Step 5:默认分组:http_req_duration、http_req_failed、http_reqs 若有 name tag 则 by (name, status),否则 by (url, status),因为不同 endpoint 基线不同,混在一起会掩盖每 endpoint 漂移。
- Step 5:默认分组:iteration_duration(多 scenario test)按 by (scenario),因为 browser 和 protocol scenario 的 duration 差异很大。
- Step 5:默认分组:自定义 trend 且有 tags 时按 by (<the tag>),用户打什么 tag 通常就是关心什么。
- Step 5:构造 grouped query 前先通过 labels endpoint(metrics.md §4)和 label-values endpoint(metrics.md §5)发现可用 labels;不要只靠读脚本假设 labels,tag 重命名或重构会静默改变 label 空间。示例:GET /cloud/v5/test_runs/{id}/labels?match[]=browser_web_vital_lcp;然后 GET /cloud/v5/test_runs/{id}/label/url/values。
- Step 5:仅当分组不增加信息时才回退到裸 aggregate(无 by),例如 vus、load_generator_cpu_percent、所有请求同一 URL 的单目标 test。
- Step 5:响应中的 test_run_id 作为 label,用于把每个值映射回 Step 3 的 run 时间戳;grouped query 对每个 (group, run) 组合返回一个 series,展平为整洁的 rid x group 表供 Step 7 计算趋势。
- Step 5:若 run ID 太多无法放进单个 URL(数百个),将查询按 50 个 run ID 分批并合并结果。
- Step 6:获取 test 当前 script(按 k6-manage Section 5),解析 export const options = { thresholds: {...} } 块。
- Step 6:记录每个 threshold 的 metric name 和 selector(如 http_req_duration{name:homepage})、condition(如 p(95)<500)、是否设置 abortOnFail。
- Step 6:检查最近一次 run 的 threshold 结果,查看当前哪些 threshold 通过/失败。
- Step 6:并非所有 metric 都有 threshold,这没问题;无 threshold 的 metrics 仍做趋势分析,只是不做 headroom 计算。
- Step 7:检测拐点并以确定性方式排除脚本变更;在下结论前寻找 metric 值的不连续点,即同一天多个 metric 对齐的突然跳变或下跌。
- Step 7:发现拐点时不要猜脚本是否改变;用 run-bundled script endpoint(GET /cloud/v6/test_runs/{id}/script,k6-manage §5)在边界前后取快照,注意用 run-scoped endpoint 而不是 load-test endpoint(后者只显示当前版本),并用 shasum -a 256 比较。
- Step 7:sha256 比较命令:gcx --context <ctx> api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/<before_id>/script > /tmp/before.bin;gcx --context <ctx> api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/<after_id>/script > /tmp/after.bin;shasum -a 256 /tmp/before.bin /tmp/after.bin。
- Step 7:对多 run 拐点,为过渡期间每个 run 计算 hash;若 N 个连续 run 共享一个 hash、之后 N 个共享另一个,则有干净的 before/after 边界;若 hash 中途变化,说明 test 被编辑了多次。
- Step 7:若 sha256 不同,test script 已变,拐点可能是 test 侧产物而非服务回归;在边界处把分析拆成不同 era,并在每个 era 内单独计算趋势。
- Step 7:跨 script 变更比较 metric 会产生误导趋势;例如 P95 从 3,000ms 降到 150ms 不是 improvement,如果 script 只是停止访问慢 endpoint。
- Step 7:在报告中明确说明 eras,并把建议集中在最近的 era。
- Step 7:若 sha256 相同,脚本 byte-identical,回归是 test 外部原因(服务侧、基础设施或 load-zone);这是高置信信息,带入 Step 9 服务侧关联,而不是把 did the test change? 留作开放问题。
- Step 7:在每个检测到的拐点都运行这个 5 秒确定性 sha256 diff,而不只在用户询问时运行。
- Step 7:对每个 metric 构建按时间排序的 (run_timestamp, value) 序列。
- Step 7:计算基础统计:所有 run 的 mean、standard deviation、min、max。
- Step 7:计算 current value(最近一次 run)和 baseline value(窗口内最旧 run,或用前 3 个 run 的均值更稳定)。
- Step 7:趋势方向:把 run 分成两半(时间窗口前半和后半),比较两半均值;Degrading 为后半均值恶化 >10%(延迟/错误更高,成功率更低);Improving 为后半均值改善 >10%;Stable 为变化在 10% 内;Volatile 为标准差超过均值的 25%,不论方向。
- Step 7:10% 和 25% 阈值只是起点;如果用户 test 容差很紧或 metric 很噪声,调整并解释原因。
- Step 7:变化率表示为每周百分比变化:((recent_mean - baseline_mean) / baseline_mean) * 100 / weeks_in_window;以归一化不同窗口大小。
- Step 7:异常检测:标记任何 metric value 距总体均值超过 2 个标准差的 run;这些是值得单独调查的潜在拐点。
- Step 8:对有 threshold 的 metrics(来自 Step 6)计算 headroom:headroom_pct = ((threshold_value - current_value) / threshold_value) * 100。
- Step 8:分类 headroom:Comfortable (>50%) 远在限制内;Adequate (20-50%) 健康但值得监控;Thin (<20%) 若趋势继续有突破风险;Breached (<0%) 已失败。
- Step 8:对退化且 headroom 很薄的 metrics,如果当前变化率继续,估算何时突破 threshold:weeks_until_breach = headroom_absolute / rate_of_change_per_week。
- Step 8:这是粗略 projection,不是预测;表述为 at the current rate of degradation, this metric could breach in approximately N weeks。
- Step 9:若 Step 7 发现退化,主动提供(不要自动运行)服务侧数据关联,以区分 service degradation(修服务)、test-environment changes(load-zone 延迟、LG exhaustion)和 script changes(更慢的编辑);先呈现发现并询问。
- Step 9:通过 gcx 转交 debug-with-grafana,查询同一窗口的服务 Prometheus metrics 和 Loki logs;寻找服务错误率变化、上游延迟、资源压力(CPU/memory/pools)以及与拐点重合的 deploys。
- Step 9:当服务无可观测性(第三方或别的团队的服务,无 Prometheus job、Loki stream 或 probe),回退到客户端信号,仍可定位回归。
- Step 9:Browser tests:比较 before/after run 的 Tempo iteration traces(k6-manage §7,/api/v1/tempo/api/search + /traces/{id});span-name rollup、slowest spans 和 per-URL navigation durations 可把回归定位到 URL、locator action 或 asset;web vitals 是 web_vital.* span attributes,直接读取。
- Step 9:Protocol tests:比较 http_req_duration by (name, status) 和 http_req_failed by (name, status);某个 named request 回归指向该 endpoint;拆分 http_req_waiting(server time)与 http_req_receiving(transfer)以区分慢处理与慢下载。
- Step 9:Payload corroboration(两者都适用):查询 data_received / browser_data_received;延迟升 + payload 升 -> server content changes;延迟升 + payload 稳定 -> server processing changes;payload 间歇 -> flaky cache 或 A/B test。
- Step 9:优先服务端关联,因为它直接回答 why;回退方法回答 where 和 what kind of change,并可为负责团队创建 ticket。
- Step 10:始终以结构化报告呈现发现;永远不要直接应用变更。
- 报告模板:标题为 # Trend Analysis: {test_name},并列出 Test ID: {test_id}、Analysis window: {start_date} to {end_date} ({N} runs analyzed)、Overall health: {Healthy | Watch | Degrading | Critical}。
- 报告模板 Run Summary:表格列 Period、Runs、Passed、Failed、Pass Rate;行 First half、Second half。
- 报告模板 Metric Trends:表格列 Metric、Type、Current、Baseline、Change、Trend、Threshold、Headroom。
- 报告模板 Flagged Issues:每个问题写 ### 1. {metric_name}: {classification},并列出 Current、Baseline、Change、Threshold、Headroom、Rate of change、Projected breach、Anomalous runs(含 run_ids 和 dates,如有)。
- 报告模板 Threshold Recommendations:表格列 Metric、Current Threshold、Recommended、Rationale;rationale 说明例如当前 P95 是 380ms,收紧到 420ms 可在当前性能上方留 10% headroom,并更早暴露进一步退化。
- 报告模板 Suggested Next Steps:列出 Investigate service side(如 P95 增加 52%,考虑加载 debug-with-grafana)、Deep-dive run {run_id}(某日异常 P95 spike,考虑加载 k6-cloud-investigate-test)、Tighten thresholds(2 个 metrics 有 >30% headroom 可收紧,考虑加载 k6-test-maintenance)。
- Overall health 分类:从最差 metric 推导;Healthy 所有 metrics stable/improving 且 headroom comfortable/adequate;Watch 至少一个 degrading 但 headroom 仍 adequate;Degrading 至少一个 degrading 且 thin headroom;Critical 至少一个 threshold breached,或多个 metrics degrading 且 thin headroom。
- Threshold 建议原则:只收紧,不放松,除非用户要求;放松 threshold 会掩盖问题。
- Threshold 建议原则:以该 metric 近期 P95 上方 10-20% headroom 为目标;足够容纳正常波动,又足够紧以捕获真实退化。
- Threshold 建议原则:用 second-half mean 作为 baseline,而不是单个最近 run(可能是离群值)。
- Threshold 建议原则:尊重用户意图;若 thresholds 当前非常松(>100% headroom),可能是有意宽松,提及收紧机会但不要强推,用户了解自身上下文。
- Threshold 建议原则:考虑 grouped thresholds;若 test 使用 tag-based thresholds(如 http_req_duration{name:homepage}),且 endpoint 之间趋势不同,建议 per-endpoint thresholds。
- Gotchas:zero-observation thresholds 在 k6 默认通过;若 metric 看似通过但无数据,要标记,threshold 实际未被评估。
- Gotchas:metric type 跨 run 变化时(如 script refactor),multi-run aggregate endpoint 使用最新 type;较早 run 用错方法查询会返回空;检测到就标记。
- Gotchas:不完整 run 会扭曲趋势;aborted 或 timed_out run 通常 duration 更短、iteration 更少,产生不具代表性的 metric 值;默认排除。
- Gotchas:LG resource metrics;load_generator_cpu_percent 和 load_generator_file_handles 上升可能表示 test 超出其 load generator 分配,而不是服务退化;单独指出。
- Gotchas:rate metric 方向;对 ratio 类型 rate metrics(如 check pass rates),degrading 意味着值下降(通过更少),与延迟 metric 方向相反。
适用边界 · 注意事项
- 单个 run 的失败根因排查:应加载 k6-cloud-investigate-test,而不是做多 run 趋势分析。
- 需要编辑脚本、直接应用阈值修改或创建新测试脚本:应分别加载 k6-test-maintenance 或使用测试创建流程。
- 可用 run 少于 3 个,或需要直接查询服务端指标做可观测关联:前者趋势无意义,后者应转交 debug-with-grafana。