schema_version: 1
id: top-tidb-p99-latency-nodes-in-saas01-during-latest-window
title: Top TiDB P99 latency nodes in saas01 during the latest completed Beijing 11:00-11:05 window
status: active
owner: codex
evaluation:
  mode: adhoc_evidence
environment:
  profile: stable-dedicated
  cluster_label: saas01
  cluster_id: '10989049060142230334'
  cluster_type: dedicated
  tidb_version: v8.5.x
time_window:
  resolved_by_output: resolved_window
runtime:
  hooks:
  - id: resolve_runtime_window
    stage: before_acp
    kind: python_script
    path: runtime_hook.py
    output_id: resolved_window
    args:
      - resolve-window
      - --cluster-id
      - '{{environment.cluster_id}}'
      - --cluster-label
      - '{{environment.cluster_label}}'
      - --local-hour
      - '11'
      - --local-minute
      - '0'
      - --duration-minutes
      - '5'
      - --step-seconds
      - '60'
      - --top-n
      - '3'
  - id: build_runtime_reference
    stage: before_judge
    kind: python_script
    path: runtime_hook.py
    output_id: reference_answer
    args:
      - build-reference
      - --cluster-id
      - '{{environment.cluster_id}}'
      - --cluster-label
      - '{{environment.cluster_label}}'
      - --start
      - '{{runtime.resolved_window.start}}'
      - --end
      - '{{runtime.resolved_window.end}}'
      - --step-seconds
      - '60'
      - --top-n
      - '3'
prompt:
  text: |
    帮我看下 {{environment.cluster_label}} 这个集群（{{environment.cluster_id}}）在 {{runtime.resolved_window.start}} 到 {{runtime.resolved_window.end}} 这 5 分钟里，SQL 尾延迟最重的 TiDB 节点是谁。

    先找出前 3 个节点以后，再对这 3 个节点继续补充看 5 个更细的 P99 信号：
    计划构建耗时、分布式执行耗时、TiDB client 侧的 kv_get request duration、PD client 侧的 TSO request duration、Go GC pause 耗时。

    另外再统一补 2 个 cluster-level 的 P99 信号，不用按 TiDB 节点拆分，直接看整个集群里：
    1. 所有 TiKV 节点的 kv_get gRPC request handle 时间均值
    2. 所有 PD 节点的 TSO request handle 时间均值

    规则严格如下：
    1. 对每个节点，先取这 5 分钟内 1 分钟粒度的 P99 latency 序列，再计算该节点在整个窗口内的平均值。
    2. 对上面那 5 个节点级补充信号，也都按同样方式：先取 1 分钟粒度的 P99 序列，再计算整个窗口内的平均值。
    3. 对那 2 个 cluster-level 信号，分别对当前集群里的每个 TiKV 或 PD 节点，先计算该节点在这 5 分钟内 1 分钟粒度的 P99 序列均值，再对所有相关节点的这个窗口均值做算术平均。
    4. 先按未四舍五入的原始 `avg_p99_latency_s` 从高到低排序取前 3；只有原始平均值完全相同，才按节点名字典序。
    5. 节点名必须输出 K8s pod 名，例如 `db-tidb-1`。
    6. 如果关键 latency 指标查不到、查出来整包都是空序列，或者这 5 个节点级补充信号、这 2 个 cluster-level 信号里有任意一个数据缺失，不要猜，直接认为证据不足。

    我只看最后结果。最终只输出一个 `json` 代码块，字段必须严格为：
    `cluster_id`、`window`、`evidence_sufficient`、`cluster_avg_tikv_grpc_request_handle_p99_s`、`cluster_avg_pd_tso_request_handle_p99_s`、`top_nodes_by_avg_p99_latency`

    `top_nodes_by_avg_p99_latency` 必须严格包含 3 个元素。每个元素都只能包含：
    `node`、`avg_p99_latency_s`、`avg_plan_build_p99_s`、`avg_distributed_execution_p99_s`、`avg_kv_request_p99_s`、`avg_get_tso_wait_p99_s`、`avg_gc_stw_pause_p99_s`

    所有有数值的 `*_s` 字段都保留 6 位小数。

    不要输出额外字段，不要输出额外解释，也不要把说明写进 JSON。

    JSON 结构如下：

    ```json
    {
      "cluster_id": "10989049060142230334",
      "window": {
        "start": "2026-01-01T03:00:00Z",
        "end": "2026-01-01T03:05:00Z"
      },
      "evidence_sufficient": true,
      "cluster_avg_tikv_grpc_request_handle_p99_s": 0.003210,
      "cluster_avg_pd_tso_request_handle_p99_s": 0.000789,
      "top_nodes_by_avg_p99_latency": [
        {
          "node": "db-tidb-1",
          "avg_p99_latency_s": 0.123456,
          "avg_plan_build_p99_s": 0.001234,
          "avg_distributed_execution_p99_s": 0.056789,
          "avg_kv_request_p99_s": 0.012345,
          "avg_get_tso_wait_p99_s": 0.000456,
          "avg_gc_stw_pause_p99_s": 0.000123
        }
      ]
    }
    ```

    如果证据不足，请把 `evidence_sufficient` 设为 `false`，并把 `top_nodes_by_avg_p99_latency` 设为空数组。那 2 个 cluster-level 字段如果有值就照常返回；如果对应证据本身缺失，就填 `null`。
tags:
- tidb
- latency
- p99
- structured-output
- adhoc-evidence
- saas01
case_tier: P1
cost_tier: low
followup:
  scheduled_max_followups: 0
execution:
  acp_bash_timeout_s: 300
