performance-rca

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Performance RCA

性能根因分析

Explain the observed performance problem: which workload changed, which code path accounts for it, and what evidence supports the mechanism. A hotspot is a location; an anomaly is a lead; neither alone proves a root cause. Stop at the strongest supported conclusion, including an inconclusive result. Code changes and proactive optimization are separate tasks.
解释观察到的性能问题:哪个工作负载发生了变化、哪条代码路径导致了该问题,以及有哪些证据支持其机制。热点是一个位置;异常是一条线索;二者单独都不能证明根因。应在证据支持的最强结论处停止,包括得出结论不充分的结果。代码修改和主动优化属于另外的任务。

Investigation contract

调查约定

  1. Follow Sections 1–5 in order. Reuse verified evidence from an earlier step or referring investigation; do not repeat discovery merely to satisfy the sequence. Establish each step's prerequisites before interpreting its result.
  2. Fix the context, datasource, UTC windows, selectors, and profile type before comparison. Discover missing identifiers; never invent them. Record any justified change to the scope or comparison.
  3. Qualify the control in Section 2 before claiming a regression. Without one, continue only to current cost attribution and label the comparison missing.
  4. Distinguish empty results, unsupported capabilities, and query failures. Apply Section 1's exits to the affected profiling path; use its documented fallbacks only when their prerequisites hold.
  5. Select output formats explicitly: JSON for discovery/metrics, table to rank functions, DOT to trace callers and callees, and pprof for export. Retain diagnostics and limits.
  6. Always produce Section 5's report, including after an exit. Fill unsupported fields with
    unknown
    ,
    not measured
    , or
    not applicable
    , plus a reason. A missing measurement must never become evidence that the service is healthy.
  1. 按顺序执行第 1–5 节。复用前一步或所引用调查中已经验证的证据;不要仅仅为了满足执行顺序而重复发现过程。解释每一步的结果前,先确认该步骤的前提条件。
  2. 比较前固定上下文、数据源、UTC 时间窗口、选择器和 profile 类型。发现缺失的标识符;绝不能臆造。记录任何有依据的范围或比较调整。
  3. 声称发生回退前,必须验证第 2 节中的对照条件。如果没有合格的对照样本,则只能继续分析当前成本位置,并将比较标记为缺失。
  4. 区分空结果、不支持的功能和查询失败。将第 1 节的退出条件应用到受影响的 profiling 路径;仅在前提条件成立时使用其中记录的 fallback。
  5. 明确选择输出格式:发现和指标使用 JSON,函数排名使用 table,追踪 callers 和 callees 使用 DOT,导出使用 pprof。保留诊断信息和限制条件。
  6. 始终生成第 5 节的报告,包括提前退出时。对于不支持的字段,填入
    unknown
    、
    not measured
    或
    not applicable
    ,并附上原因。缺失的测量结果绝不能被当作服务健康的证据。

1. Preserve the question and check usable profiles

1. 保留问题并检查可用的 profiles

Reuse the context, datasource, service, symptom, incident window, deployment facts, and trace/profile links supplied by the user or a referring skill. Pin absolute UTC incident and baseline times. Derive a missing incident interval from timestamped symptom evidence, or ask for it before querying. Carry the same
--context <context>
on remote commands (omitted below), and pass the datasource UID explicitly. Keep the investigation read-only; do not switch contexts or change collection.
bash
gcx help-tree profiles -o text
The examples below need gcx v1.3.0 or later; check with
gcx --version
. If gcx is missing or older, ask the user to install or upgrade it from https://github.com/grafana/gcx before continuing. Do not guess command renames or silently drop time filters. Commands, flags, and output formats can still be unsupported by the backend; Section 4 and the advanced reference describe those fallbacks.
bash
undefined
复用用户提供或所引用 skill 提供的上下文、数据源、服务、症状、事故窗口、部署事实以及 trace/profile 链接。固定绝对 UTC 时间的事故时间和基线时间。可以根据带时间戳的症状证据推导缺失的事故区间;否则应在查询前询问用户。远程命令必须携带相同的
--context <context>
(下文省略),并显式传入数据源 UID。保持调查只读;不得切换上下文或更改采集配置。
bash
gcx help-tree profiles -o text
以下示例需要 gcx v1.3.0 或更高版本;使用
gcx --version
检查。如果 gcx 缺失或版本过旧,请让用户从 https://github.com/grafana/gcx 安装或升级,然后继续。不得猜测命令重命名,也不得静默删除时间过滤器。命令、参数和输出格式仍可能不受后端支持;第 4 节和高级参考说明了相应的 fallback。
bash
undefined

Discover only if the datasource UID is unknown; choose the target environment.

Discover only if the datasource UID is unknown; choose the target environment.

gcx datasources list -t grafana-pyroscope-datasource -o json gcx profiles data-range -d <pyro-uid> -o json gcx profiles list-profile-types -d <pyro-uid>
--from <incident-from> --to <incident-to> -o json

CLI support does not imply backend support. `data-range` returns tenant-wide
`dataIngested`, `oldestProfileTime`, and `newestProfileTime` (Unix
milliseconds; zero means unknown). These bounds do not prove that the selected
service or lens has continuous coverage. Do not assume a fixed retention
period.

Apply these outcomes before proceeding. Every exit stops the affected profile
queries and produces the Section 5 report; other usable signals may continue
through gcx's bundled `debug-with-grafana` skill
(`gcx agent skills get debug-with-grafana`) with the missing-evidence question
made explicit.

- **EXIT A — profiling unavailable:** no target datasource, missing access, or
  a required CLI capability is unavailable. Record the exact limitation; use
  `gcx login` and `gcx config check` for missing setup or access, or a
  compatible gcx build for a CLI mismatch.
- **EXIT B — no ingestion reported:** a successful stats response says
  `dataIngested: false`. Report the instrumentation/data gap,
  not service health.
- **EXIT C — incident not covered:** the incident has no overlap with known
  queryable bounds. Report both ranges; do not replace the incident with today.
  For partial overlap, analyze only that overlap, record the coverage gap, and
  limit conclusions to the observed interval.
- **EXIT D — no usable incident profiles:** after checking the selector, window,
  and lens against discovered facts, incident samples remain absent or zero. A
  missing baseline alone is handled in Section 2, not by this exit. Report the
  unresolved coverage/instrumentation gap, not proof of zero cost.

**Continue with scoped checks** when stats are absent, unsupported, or have
unknown bounds. Missing stats alone must not block usable type/profile queries.
These queries still need matching samples before they can support attribution.

For query errors, retain the operation and diagnostic. Correct a demonstrated
selector/flag mistake; use a documented fallback for unsupported capabilities.
Do not retry authentication failures or vary selectors blindly. A failed query
is not an empty successful result.
gcx datasources list -t grafana-pyroscope-datasource -o json gcx profiles data-range -d <pyro-uid> -o json gcx profiles list-profile-types -d <pyro-uid>
--from <incident-from> --to <incident-to> -o json

CLI 支持并不意味着后端也支持。`data-range` 返回租户范围的 `dataIngested`、`oldestProfileTime` 和 `newestProfileTime`(Unix 毫秒;零表示未知)。这些边界不能证明选定的服务或 lens 具有连续覆盖。不得假设固定的保留期。

继续之前先应用以下结果。每个退出条件都会停止受影响的 profile 查询并生成第 5 节报告;其他可用信号可以继续通过 gcx 内置的 `debug-with-grafana` skill(`gcx agent skills get debug-with-grafana`)进行查询,并明确提出缺失证据的问题。

- **EXIT A — profiling 不可用:**不存在目标数据源、缺少访问权限,或所需的 CLI 功能不可用。记录确切限制;对于缺失的配置或访问权限,使用 `gcx login` 和 `gcx config check`;对于 CLI 不匹配,使用兼容的 gcx 构建版本。
- **EXIT B — 未报告数据摄取:**成功的 stats 响应显示 `dataIngested: false`。报告 instrumentation/data 缺口,而不是服务健康状况。
- **EXIT C — 事故未被覆盖:**事故时间与已知可查询边界没有重叠。报告两个时间范围;不要用今天代替事故时间。对于部分重叠的情况,只分析重叠区间,记录覆盖缺口,并将结论限制在已观察到的区间内。
- **EXIT D — 没有可用的事故 profiles:**根据已发现的事实检查选择器、窗口和 lens 后,事故样本仍然缺失或为零。仅有基线缺失的情况由第 2 节处理,不适用此退出条件。报告尚未解决的覆盖或 instrumentation 缺口,而不是将其视为零成本的证据。

**当 stats 缺失、不支持或边界未知时,继续执行限定范围的检查。**仅缺少 stats 不应阻止有效的类型或 profile 查询。这些查询仍需匹配的样本才能支持归因。

对于查询错误,保留操作和诊断信息。如果已经证明选择器或参数存在错误,则予以修正;对于不支持的功能,使用已有记录的 fallback。不要重试认证失败,也不要盲目改变选择器。失败的查询不等同于成功返回的空结果。

2. Choose the lens and a qualified comparison

2. 选择 lens 和经过验证的比较

Copy exact profile type IDs from discovery, including their units. Discover labels rather than assuming Prometheus jobs, Tempo service names, Kubernetes workloads, and Pyroscope
service_name
have identical values.
SymptomAvailable lens to look forInterpretation limit
CPU high or CPU-bound latencyCPU timeDoes not measure all request latency, scheduling delay, or throttling
Allocation/GC pressureAllocated bytes/objectsChurn is not retained heap or a memory leak
Growing heap/OOMIn-use bytes/objects, alongside allocationsLive-heap samples are snapshots; not process RSS, native memory, or retention ownership
Contention or blocked workMutex/block delay and countsRuntime-specific sampling and attribution; not CPU time
Suspected goroutine/thread leakGoroutine/thread counts and stacksGrowth alone is not proof of leaked work
If the needed lens is absent, record the instrumentation gap; do not substitute CPU to rule out waiting or allocations to prove a leak.
A baseline must represent expected behavior, not simply precede the incident. Prefer equal-duration intervals with comparable request mix/rate, replica count, collection coverage, runtime, and sampling settings. Diurnal workloads may need a matching earlier time of day. Check profile types and data in the baseline window too. Compare an unaffected peer when no historical baseline is suitable. Without a qualified control, report current cost locations without claiming a regression. A stable but inefficient hot path may still explain a new symptom under increased load; an unchanged profile shape does not exonerate it.
For a deployment comparison, keep stable workload labels fixed, but select the old version/pod for the baseline when the incident's version/pod did not exist. Record both selectors and why they are comparable. Never compare an absent old pod/version with a populated new one and call it an infinite regression.
An anomaly result can supply the service, lens, onset, affected labels, and a candidate baseline. Preserve its link, interval, observed/expected values and score if supplied; validate them with profiles and symptom evidence. Read advanced analysis for the anomaly entry path; it requires no anomaly detector to run this skill.
从发现结果中复制确切的 profile type ID,包括其单位。发现标签,而不要假定 Prometheus jobs、Tempo service names、Kubernetes workloads 和 Pyroscope
service_name
的值完全相同。
症状可查找的 lens解读限制
CPU 高负载或受 CPU 限制的延迟CPU time(CPU 时间)无法测量所有请求延迟、调度延迟或 throttling
分配或 GC 压力Allocated bytes/objects(分配字节数/对象数)Churn 不等于保留堆内存或内存泄漏
堆内存增长或 OOMIn-use bytes/objects(使用中字节数/对象数),并结合分配数据存活堆样本是快照;不是进程 RSS、原生内存或引用保留关系
资源争用或工作阻塞Mutex/block delay and counts(互斥锁/阻塞延迟与计数)采样和归因取决于具体 runtime;不等于 CPU 时间
怀疑存在 goroutine/thread 泄漏Goroutine/thread counts and stacks(goroutine/thread 数量与栈)数量增长本身不能证明存在泄漏工作
如果缺少所需 lens,记录 instrumentation 缺口;不得使用 CPU 数据排除等待问题,也不得使用分配数据证明存在泄漏。
基线必须代表预期行为,而不能只是事故发生前的时间段。优先选择时长相等且请求组合或请求率、副本数量、采集覆盖率、runtime 和采样设置相当的区间。存在日内周期的工作负载可能需要匹配一天中更早的时段。也要检查基线窗口中的 profile 类型和数据。如果没有合适的历史基线,则比较未受影响的同类服务。没有合格的对照样本时,只报告当前成本位置,不要声称发生回退。稳定但效率低下的热点路径,在负载增加后仍可能引发新症状;profile 形态未变化也不能为其开脱。
进行部署比较时,保持稳定的工作负载标签不变;但如果事故中的版本或 Pod 当时尚不存在,应选择旧版本或旧 Pod 作为基线。记录两个选择器及其可比性依据。绝不能将不存在或没有数据的旧 Pod/版本与有数据的新 Pod/版本比较,并将其称为无限回退。
异常结果可以提供服务、lens、开始时间、受影响标签和候选基线。保留其链接、区间、观测值、预期值和分数(如有);再使用 profiles 和症状证据进行验证。阅读高级分析中的异常入口路径;运行此 skill 不需要异常检测器。

3. Localize the change: service → workload slice

3. 定位变化:服务 → 工作负载切片

Start with the known suspect, rather than a tenant-wide leaderboard. If the service is unknown, discover
service_name
values with
profiles labels
, then rank within the known environment; use a tenant-wide query only if necessary.
bash
gcx profiles labels -d <pyro-uid> \
  --from <incident-from> --to <incident-to> -o json
gcx profiles labels -d <pyro-uid> --label service_name \
  --from <incident-from> --to <incident-to> -o json
从已知嫌疑对象开始,而不是使用租户范围的排行榜。如果服务未知,通过
profiles labels
发现
service_name
值,然后在已知环境内进行排名;仅在必要时使用租户范围查询。
bash
gcx profiles labels -d <pyro-uid> \
  --from <incident-from> --to <incident-to> -o json
gcx profiles labels -d <pyro-uid> --label service_name \
  --from <incident-from> --to <incident-to> -o json

Establish onset and coverage; repeat for the baseline window.

Establish onset and coverage; repeat for the baseline window.

gcx profiles metrics -d <pyro-uid> '{service_name="<suspect>"}'
--profile-type <lens> --from <incident-from> --to <incident-to> -o json
gcx profiles metrics -d <pyro-uid> '{service_name="<suspect>"}'
--profile-type <lens> --from <incident-from> --to <incident-to> -o json

Pick a discovered label that can distinguish affected/unaffected workloads.

Pick a discovered label that can distinguish affected/unaffected workloads.

gcx profiles metrics -d <pyro-uid> '{service_name="<suspect>"}'
--profile-type <lens> --from <incident-from> --to <incident-to>
--top --group-by <label> --limit 20 -o json

Use `profiles series` to discover actual label combinations for a service
without requiring a profile type. See
[scoped series discovery](references/advanced-analysis.md#scoped-series-discovery)
for label projection. Tenant-wide label inventories alone do not prove labels
coexist on the suspect.

Repeat the chosen grouping for the baseline. Leaderboards are capped candidates,
not a fleet census; missing groups may have fallen outside the limit. A single
group establishes no peer comparison. Similar totals do not establish uniform
per-instance behavior, and the largest group may simply serve more traffic or
contain more replicas. Use request counts or replica exposure from existing
metrics when needed; if unavailable, state the confounder. Do not use a fixed
ratio threshold to declare a slice anomalous.

Use time-series values to check persistence/onset; `--top` collapses the window.
Keep units and aggregation semantics explicit, especially for live-heap or
count snapshots. Do not sum snapshot values into "bytes allocated" or infer
request-normalized cost from raw profile totals.
gcx profiles metrics -d <pyro-uid> '{service_name="<suspect>"}'
--profile-type <lens> --from <incident-from> --to <incident-to>
--top --group-by <label> --limit 20 -o json

使用 `profiles series` 发现服务的实际标签组合,无需指定 profile 类型。有关标签投影,请参阅[限定范围的 series 发现](references/advanced-analysis.md#scoped-series-discovery)。仅有租户范围的标签清单,不能证明这些标签同时存在于嫌疑服务上。

对基线重复所选分组。排行榜仅包含数量受限的候选项,并不是整个集群的普查结果;缺失的分组可能只是落在 limit 之外。单个分组不能构成同类服务比较。相似的总量不能说明每个实例的行为一致,最大的分组也可能只是承载了更多流量或包含更多副本。必要时使用现有指标中的请求计数或副本暴露量;如果无法获取,则说明相关混淆因素。不要使用固定比例阈值判定某个 slice 异常。

使用时间序列值检查问题是否持续存在及其开始时间;`--top` 会折叠整个窗口。明确说明单位和聚合语义,尤其是存活堆或计数快照。不要将快照值相加后称为“已分配字节数”,也不要根据原始 profile 总量推断按请求归一化后的成本。

4. Locate the changed application stack

4. 定位发生变化的应用调用栈

Run both queries for the incident selector below and for the qualified baseline selector/window. Omit the slice matcher when analyzing the whole service.
bash
undefined
对下面的事故选择器以及经过验证的基线选择器和窗口运行两种查询。分析整个服务时,省略 slice matcher。
bash
undefined

Rank functions.

Rank functions.

gcx profiles query -d <pyro-uid>
'{service_name="<suspect>",<label>="<value>"}'
--profile-type <lens> --from <incident-from> --to <incident-to> -o table
gcx profiles query -d <pyro-uid>
'{service_name="<suspect>",<label>="<value>"}'
--profile-type <lens> --from <incident-from> --to <incident-to> -o table

Trace callers and callees of the ranked functions.

Trace callers and callees of the ranked functions.

gcx profiles query -d <pyro-uid>
'{service_name="<suspect>",<label>="<value>"}'
--profile-type <lens> --from <incident-from> --to <incident-to> -o dot

Take function rankings and shares from the table. It aggregates each function
and lists the top 20 by SELF. Its PERCENTAGE column is SELF divided by the
profile total, not the function TOTAL share. The table omits everything past
the top 20, so to total the share of a set of functions, such as all GC
functions, sum SELF over the full profile from `-o json` or a pprof export.
Names longer than 60 characters are cut and end in `...`; take the full name
from the matching DOT node before reporting or interpreting it.

Use DOT for caller/callee context, source locations, and full function names.
Its nodes can be single source lines (`file.go:line`), so one function may
appear as several nodes. A label splits the function name across lines,
starting with the last element of its package path, then reads
`self (%) of cumulative (%)`, or a single value when they are equal. Do not
rank functions or read self shares from DOT nodes. gcx falls back
to table output with a warning when the backend explicitly rejects DOT as
unsupported or returns a flame graph instead. Other errors still fail the query.
Inspect the returned format and retain stderr. JSON encodes flame-graph wire
data, not the human function table; agent output may instead reference a spill
file that must be read.

DOT is pruned by default; dotted edges can skip intermediate frames. When
caller context is missing, repeat the same query with `-o dot --max-nodes 250`
in both windows. This raises the node limit; it does not guarantee an unpruned
graph. Neither format can rule out a missing path. For ambiguous attribution or
numerical differences, read
[pprof comparison](references/advanced-analysis.md#pprof-comparison) and export
both profiles. Do not assume an exported profile repairs collection gaps.

Interpret the evidence with these constraints:

- Compare absolute cost and share in each window, with units and a denominator.
  Equal shares can hide doubled cost; larger shares can reflect other work
  disappearing. Percentages are not request latency or proof of regression.
- Self/flat means work at that frame; total/cumulative includes descendants.
  Use caller/callee context to locate a meaningful application path. Ancestor
  totals overlap: do not add them or assign runtime work to a guessed caller.
- Runtime symbols suggest mechanisms to test. `mallocgc` suggests allocation
  work; GC workers may run separately from allocation sites; `nanotime` alone
  does not prove busy-waiting. CPU samples in `futex`/locks do not measure time
  asleep. Confirm waiting with a supported wait lens and other evidence.
- In Go, heap stacks identify allocation sites, not the object retaining
  references. Mutex profiles attribute contention to the holder/unlock path;
  block profiles to the waiter. Verify the actual runtime semantics before
  transferring this interpretation to another language or collector.

When a matching checkout/build is available, inspect the implicated function to
validate the mechanism. Read profile locations and verified deployment revision
metadata; do not assume a Build ID is a Git SHA or that `service_repository`
always exists. Report file:line only when symbolization and revision support it;
otherwise retain function-level attribution and say what is missing. Do not
edit source as part of this investigation.
gcx profiles query -d <pyro-uid>
'{service_name="<suspect>",<label>="<value>"}'
--profile-type <lens> --from <incident-from> --to <incident-to> -o dot

函数排名和占比应取自 table。它会聚合每个函数,并按 SELF 列出前 20 个。其 PERCENTAGE 列是 SELF 除以 profile 总量,而不是函数的 TOTAL 占比。Table 会省略第 20 名之后的所有内容,因此,要计算一组函数(例如所有 GC 函数)的总占比,应在完整的 `-o json` profile 或 pprof 导出结果上求 SELF 之和。超过 60 个字符的名称会被截断并以 `...` 结尾;报告或解读前,应从匹配的 DOT 节点获取完整名称。

使用 DOT 查看 caller/callee 上下文、源代码位置和完整函数名。其节点可能是单行源码(`file.go:line`),因此一个函数可能显示为多个节点。标签会将函数名拆成多行,先从包路径的最后一个元素开始,然后显示 `self (%) of cumulative (%)`,两者相等时显示一个值。不得根据 DOT 节点排名函数或读取 self 占比。当后端明确拒绝 DOT(不支持)或返回 flame graph 时,gcx 会发出警告并回退到 table 输出。其他错误仍会导致查询失败。检查实际返回格式并保留 stderr。JSON 编码的是 flame graph 传输数据,而不是便于阅读的函数表;agent 输出可能改为引用一个 spill 文件,该文件必须读取。

默认会对 DOT 进行剪枝;带点的边可能跳过中间栈帧。缺少 caller 上下文时,在两个窗口中使用相同查询并加上 `-o dot --max-nodes 250`。这会提高节点上限,但不能保证得到未经剪枝的图。两种格式都无法排除路径缺失。对于归因不明确或数值差异,请阅读 [pprof 比较](references/advanced-analysis.md#pprof-comparison)并导出两个 profile。不得假设导出的 profile 能修复采集缺口。

解读证据时遵循以下约束:

- 比较每个窗口中的绝对成本和占比,并明确单位和分母。相同的占比可能掩盖成本翻倍;更高的占比也可能只是因为其他工作消失了。百分比不是请求延迟,也不能证明发生回退。
- Self/flat 表示该栈帧自身执行的工作;total/cumulative 包含其后代。使用 caller/callee 上下文定位有意义的应用路径。祖先节点的 total 存在重叠:不要将其相加,也不要把运行时间归因给推测的 caller。
- Runtime 符号可用于提出需要检验的机制。`mallocgc` 表明存在分配工作;GC worker 可能独立于分配位置运行;仅有 `nanotime` 不能证明存在忙等待。`futex`/锁中的 CPU 样本不测量休眠时间。使用受支持的 wait lens 和其他证据确认等待情况。
- 在 Go 中,堆栈标识分配位置,而不是保留引用的对象。Mutex profiles 将争用归因给持有锁或执行解锁的路径;block profiles 则归因给等待者。将这些解释应用到其他语言或采集器之前,必须核实其实际 runtime 语义。

有匹配的 checkout/build 时,检查相关函数以验证机制。读取 profile 位置和经过验证的 deployment revision 元数据;不要假定 Build ID 是 Git SHA,也不要假定 `service_repository` 一定存在。只有在符号化和 revision 都能支持时,才报告 file:line;否则保留函数级归因并说明缺少什么。调查过程中不要编辑源代码。

5. Test the cause and report

5. 检验原因并生成报告

Carry the suspect path back to the original symptom. Use the relevant evidence through gcx's
debug-with-grafana
skill: request/CPU/heap trends, throttling, queueing, dependency latency, logs, configuration or deployment changes. Reuse existing findings; query only what can distinguish the leading explanation from a material alternative. For a supplied request, see trace correlation.
A deployment timestamp or detector score is correlation. Strengthen a causal claim with matching onset, a specific mechanism, affected/unaffected controls, and repeatable differences or an already-observed recovery. Do not perform a rollback or load test merely to validate the hypothesis.
Stop when the user's question is answered or missing evidence prevents further attribution. Return a root cause only when the mechanism and symptom connection are supported; otherwise return a suspected cause, cost location, or inconclusive result. Never turn "not observed in these profiles" into "not in this service".
Use this report for every outcome. Keep the field names and order; add details under Evidence only when needed to support the conclusion. A blocked or empty investigation is
inconclusive
, with the exit and missing evidence recorded. Without a qualified baseline, report measured cost locations without regression claims. Unknown fields remain explicit; do not fill them with guessed values.
text
Conclusion:     <established cause | suspected cause | cost location |
                 inconclusive> — <answer to the original question>
Exit:           <A | B | C | D | none> — <reason, if applicable>
Scope:          <context, datasource UID, service>
Lens:           <exact profile type and units>
Incident:       <UTC from/to; exact selector; observed coverage>
Baseline:       <UTC from/to; exact selector; or unavailable with reason>
Control:        <why comparable; workload/collection differences or gaps>
Slice:          <affected label/value; evidence of scope or unknown>
Location:       <application stack; file:line and revision only if verified>
Cost:           <incident vs baseline absolute values, units, aggregation>
Share:          <incident vs baseline; self/cumulative and denominator>
Normalization:  <method and measured denominator | not applied, with reason>
Mechanism:      <supported explanation or explicitly labeled hypothesis>
Evidence:       <profile artifacts/links and corroborating symptom evidence>
Counterevidence: <alternatives checked and results | not checked, with reason>
Confidence:     <high | medium | low> — <reason tied to available evidence>
Limitations:    <coverage, sampling, baseline, symbolization or access gaps>
Next action:    <smallest missing evidence or handoff question | none>
将嫌疑路径带回原始症状。通过 gcx 的
debug-with-grafana
skill 使用相关证据:请求、CPU 和堆趋势,throttling、排队、依赖延迟、日志、配置或部署变更。复用已有发现;只查询能够区分主要解释与实质性替代解释的信息。对于给定的 request,请参阅 trace 关联。
部署时间戳或检测器分数只能证明相关性。只有在开始时间吻合、机制具体、存在受影响和未受影响的对照,并且差异可重复或已经观察到恢复时,才能强化因果主张。不要仅仅为了验证假设而执行回滚或负载测试。
当用户的问题得到回答,或缺失证据阻止进一步归因时停止。只有机制与症状之间的联系得到支持时,才能返回 root cause;否则应返回 suspected cause、cost location 或 inconclusive。绝不能将“这些 profiles 中未观察到”改写成“该服务中不存在”。
所有结果都使用此报告。保留字段名称和顺序;仅在支持结论需要时在 Evidence 下添加细节。调查受阻或结果为空时应标记为
inconclusive
,并记录退出条件和缺失证据。没有经过验证的 baseline 时,只报告已测量的 cost location,不要声称发生回退。未知字段必须明确保留;不得用猜测值填充。
text
Conclusion:     <established cause | suspected cause | cost location |
                 inconclusive> — <answer to the original question>
Exit:           <A | B | C | D | none> — <reason, if applicable>
Scope:          <context, datasource UID, service>
Lens:           <exact profile type and units>
Incident:       <UTC from/to; exact selector; observed coverage>
Baseline:       <UTC from/to; exact selector; or unavailable with reason>
Control:        <why comparable; workload/collection differences or gaps>
Slice:          <affected label/value; evidence of scope or unknown>
Location:       <application stack; file:line and revision only if verified>
Cost:           <incident vs baseline absolute values, units, aggregation>
Share:          <incident vs baseline; self/cumulative and denominator>
Normalization:  <method and measured denominator | not applied, with reason>
Mechanism:      <supported explanation or explicitly labeled hypothesis>
Evidence:       <profile artifacts/links and corroborating symptom evidence>
Counterevidence: <alternatives checked and results | not checked, with reason>
Confidence:     <high | medium | low> — <reason tied to available evidence>
Limitations:    <coverage, sampling, baseline, symbolization or access gaps>
Next action:    <smallest missing evidence or handoff question | none>