mcpField
M
mz-debug-freshness

mz-debug-freshness

github.com/materializeincその他339 回インストール今日更新
リポジトリ

mz-debug-freshness について

mz-debug-freshness は Materialize の鮮度問題を調査するスキルです。依存関係と実行計画をたどって遅延の原因を特定し、対象オブジェクト、根拠、確認すべき SQL を報告します。

主な機能

  1. 01現在の遅延と過去のピークを集約
  2. 02オブジェクト間の依存をたどって遅延を追跡
  3. 03取り込み状態とハイドレーションを確認
  4. 04レプリカ負荷とオペレーターコストを分析
  5. 05実行計画を SQL に対応付け

活用シーン

  1. 01遅延の原因となるソースやシンクの特定
  2. 02継続中の遅延と回復済みピークの区別
  3. 03レプリカ競合やオペレーターの偏りの発見
  4. 04調査すべきビューと SQL の特定

MCP 対応

Materialize developer MCP server の読み取り専用ツールを使用します。query_system_catalog はカタログを検索し、query は EXPLAIN 文や introspection リレーションを実行します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/materializeinc/agent-skills --skill mz-debug-freshness

インストール後、Claude Code で/mz-debug-freshnessを入力して読み込まれたか確認します。

同梱ファイルreferences/attribution.mdreferences/dataflow-analysis.md

詳細

Freshness のデバッグ

Freshness の問題を引き起こしているオブジェクトを 1 つ見つけてください。遅延している理由を説明します。 レポートには、原因となっているオブジェクトを挙げ、証拠を示し、高コストな処理を引き起こしている SQL を指摘してください。

ツール

このスキルは、読み取り専用ツールを 2 つ公開する Materialize 開発者 MCP サーバー上で実行されます。query_system_catalog は mz_*、pg_catalog、information_schema を読み取ります。query はクラスターを受け取り、それ以外のすべてを実行します。 EXPLAIN 文と mz_introspection リレーションです。 クライアント設定では、サーバー名をプレフィックスとして付けます。たとえば、mcp__<server>__query_system_catalog のようになります。

EXPLAIN コマンド、その出力列、オペレーターのパターンについては、 references/dataflow-analysis.md を参照してください。以下の各ステップには、必要なコマンドが明記されています。

ワークフロー

digraph freshness {
    "Trigger: something is behind" [shape=ellipse];
    "Gather: ranking, status sweep, recent peaks" [shape=box];
    "What does the evidence show?" [shape=diamond];
    "Report: unhealthy source or sink" [shape=doublecircle];
    "Report: peak already recovered" [shape=doublecircle];
    "Report: nothing is behind" [shape=doublecircle];
    "What type is the object?" [shape=diamond];
    "Does one hop carry most of the lag?" [shape=diamond];
    "Is the dataflow hydrated?" [shape=octagon, style=filled, fillcolor=red];
    "Report: still hydrating, re-run later" [shape=doublecircle];
    "Report: lag enters at the root" [shape=doublecircle];
    "Does one dataflow dominate the replica?" [shape=diamond];
    "Is the load spread across dataflows?" [shape=diamond];
    "Report: replica undersized for its workload" [shape=doublecircle];
    "Report: inconclusive, list ruled out" [shape=doublecircle];
    "Is one worker carrying the operator?" [shape=diamond];
    "Report: culprit operator and SQL" [shape=doublecircle];

    "Trigger: something is behind" -> "Gather: ranking, status sweep, recent peaks";
    "Gather: ranking, status sweep, recent peaks" -> "What does the evidence show?";
    "What does the evidence show?" -> "Report: unhealthy source or sink" [label="status not running, Step 4"];
    "What does the evidence show?" -> "What type is the object?" [label="an object is behind now"];
    "What does the evidence show?" -> "Report: peak already recovered" [label="only a past peak, Step 2"];
    "What does the evidence show?" -> "Report: nothing is behind" [label="all three clean"];
    "What type is the object?" -> "Report: unhealthy source or sink" [label="table or source, Step 4"];
    "What type is the object?" -> "Does one hop carry most of the lag?" [label="view, index, sink, Step 3"];
    "Does one hop carry most of the lag?" -> "Report: lag enters at the root" [label="no"];
    "Does one hop carry most of the lag?" -> "Is the dataflow hydrated?" [label="yes, Step 5"];
    "Is the dataflow hydrated?" -> "Report: still hydrating, re-run later" [label="no"];
    "Is the dataflow hydrated?" -> "Does one dataflow dominate the replica?" [label="yes, Step 6"];
    "Does one dataflow dominate the replica?" -> "Is one worker carrying the operator?" [label="yes, Step 7"];
    "Does one dataflow dominate the replica?" -> "Is the load spread across dataflows?" [label="no"];
    "Is the load spread across dataflows?" -> "Report: replica undersized for its workload" [label="yes"];
    "Is the load spread across dataflows?" -> "Report: inconclusive, list ruled out" [label="no"];
    "Is one worker carrying the operator?" -> "Report: culprit operator and SQL" [label="skew"];
    "Is one worker carrying the operator?" -> "Report: culprit operator and SQL" [label="expensive plan"];
}

ステップ 1:証拠を集め、対象を選ぶ

対象を選ぶ前に、3 つすべての検索を実行してください。

  1. 現在の遅延は、現時点で遅延しているものを順位付けします。
  2. ステータスの一括確認は、順位付けでは見つからないものを検出します。停止したソースは現在の書き込みフロンティアを維持し、遅延を秒単位で報告するため、順位付けでは正常に見えます。ここにある行は、順位付けの結果にかかわらず問題を示しており、エラーテキストは遅延より優先されます。
  3. 最近のピークは、過去 24 時間を対象とします。順位付けが示すのは現在の状態のみなので、1 時間前に回復したピークは順位付けには残りません。

3 つの結果を合わせて確認してください。

  • ステータスの一括確認に行がある場合は、ほかの状況にかかわらずステップ 4 に進みます。
  • 順位付けで明らかに突出しているオブジェクトがあれば、それを対象とします。以下に進んでください。
  • 順位付けに偏りがなく、ステータスの一括確認にも問題がない一方で、最近のピークが平均を大きく上回るオブジェクトがある場合は、そのイベントはすでに回復しています。ステップ 2 で確認する形状と、 compute gates で確認する再起動があれば、それを添えて報告してください。
  • 3 つすべてに問題がなければ、遅延しているものはありません。そのように伝えてください。

以降のすべてのクエリでは、ID ではなく、クエリが返す完全修飾名 database.schema.object を使います。参照クエリにはすべて materialize.public.my_view というプレースホルダーが含まれています。調査対象の名前に置き換えてください。そうしないと、クエリ結果が空になり、オブジェクトがアイドル状態に見えてしまいます。名前解決を参照してください。

type 列によって進む経路が決まります。

TypePath
table、sourceステップ 4。これらにはアトリビューションの追跡結果がありません。
materialized-view、indexステップ 2。
sinkステップ 2、その後 sink status。シンクではオペレーター分析を利用できません。

ステップ 2:遅延の履歴を確認する

1 回の計測では、一時的なスパイクと持続的な問題を区別できません。 mz_wallclock_global_lag_recent_history には、過去 24 時間の 1 分ごとのサンプルが格納されています。

クエリ:references/attribution.md。

遅延の増加、一定水準での停滞、回復した単発のスパイクは、それぞれ異なる問題です。最初の 2 つについては、調査を続ける価値があります。サンプル数が 1440 未満の場合、その数はオブジェクトの経過時間を分単位で表しており、ステップ 6 で必要になります。

ステップ 3:遅延の原因をホップごとに特定する

遅延は引き継がれます。mz_internal.mz_materialization_lag を使うと、その原因を特定できます。

列意味
local_lagこのオブジェクトが直接の入力に加える遅延。
global_lagルート入力に対する遅延。
slowest_local_input_id最も遅い直接入力。ホップごとにたどります。
slowest_global_input_id最も遅いルート入力。1 回の参照で特定します。

クエリ:references/attribution.md。

各ホップを相互に比較してください。オブジェクトの global_lag の大部分を占めるホップが遅延の原因です。ステップ 4 以降では、そのホップを対象とし、最初に調査を始めたオブジェクトは対象にしません。突出したホップがなければ、遅延はルートで発生しています。ルートテーブルまたはソースを対象に、ステップ 4 に進んでください。

Step 4: 取り込み

遅延が発生しているのは、テーブルまたはソースです。

  1. ステータスとエラーテキスト:取り込み。エラーのあるソースが停止していれば、それだけで回答になります。
  2. 同じセクションでスナップショットの進行状況を確認します。snapshot_committed が false の場合、ソースは初回スナップショットの取得中であり、遅延はまったく発生していません。
  3. 同じセクションで書き込みフロンティアを確認し、進行しているかどうかを確認します。フロンティアが進行していても、ソースの問題が解消したとは限りません。ステータスとエラーテキストのほうが優先されます。

シンクの場合は、シンクのステータスを使用します。

この3つのうち、どれか1つだけで回答できる場合があります。その場合は、その内容を報告して終了してください。

エラーテキストに上流の問題が記載されているソースは、原因を特定できています。スキーマ変更との互換性がない、パブリケーションが削除された、認証情報の有効期限が切れた、などです。修正すべきなのは Materialize より上流であり、このスキルの対象外です。

Step 5: ハイドレーションを確認してレプリカを選択する

EXPLAIN ANALYZE を実行する前に、2つの点を確認します。

ハイドレーション。データフローがハイドレーション中の場合、スナップショットの処理中です。そのため、EXPLAIN ANALYZE で測定されるのは処理への追いつきであり、処理に追いついた状態の維持ではありません。mz_internal.mz_hydration_statuses でオブジェクトがハイドレーションされていないと報告された場合は、その旨を報告し、完了後に再実行するよう依頼してください。

レプリカ。すべてのレプリカは同じ処理を行うため、どれか1つを代表として選べます。2つから選ぶ場合は、処理量が少なく、最近の offline エントリがないほうを分析してください。

クエリ:references/attribution.md。

Step 6: レプリカを消費しているものを特定する

データフローはレプリカの CPU とメモリを共有するため、遅延しているオブジェクトが、無関係な別のオブジェクトによってリソース不足になっている場合があります。

EXPLAIN ANALYZE CLUSTER CPU, MEMORY を実行し、続けて WITH SKEW を付けてもう一度実行します。詳細:クラスターレベル。

total_elapsed はデータフローの開始以降の累積値です。そのため、結論を出す前に、候補の値をオブジェクトの経過時間と照らし合わせてください。object 列の値が、以降の調査で引き継ぐ名前です。global_id は一時的なもので、参照先はありません。

ランキングは、候補同士で比較してください。レプリカが費やした時間の大部分を占めるデータフローがあれば、それが Step 7 の調査対象です。最初に調べていたオブジェクトと同じかどうかは問いません。そのデータフローと次点のデータフローとの開きが、際立っていることの根拠になります。

際立ったものがなく、レプリカに余力も残っていない場合、ワークロードはレプリカの処理能力を超えています。多くのデータフローが同じレプリカを共有しており、個別に問題のあるものはありません。これが診断結果であり、使用率の数値がその根拠です。際立ったものがなく、レプリカに余力がある場合は、結論を出せません。ランキングの最上位を原因と決めつけず、除外できた可能性を報告してください。

ステップ 7:コストの高いオペレーターを特定する

そのデータフローのオペレーターをランク付けします: オペレーターのコスト。完全修飾名を指定して実行すると、データフロー自身のクラスターで処理されます。

percent_of_dataflow の大部分を占めるオペレーターから調べます。リストの値が徐々に下がっている場合、コストは分散しており、単独で答えとなるオペレーターはありません。最大のオペレーターを挙げるのではなく、その旨を伝えてください。

結果が薄い場合、2 通りの解釈ができます。オペレーター名がその違いを示します。実際の経過時間があるオペレーターが 1 つか 2 つの場合、そのインデックスのデータフローは別のオブジェクトの出力を整えるだけです。ステップ 8 でインデックス対象を特定し、そちらを分析してください。コストが null のオペレーターが 1 つだけの場合、そのパススルーはオペレーターをまったく持ちません。処理は Read または Arranged の行に記載されたオブジェクト内にあり、そのオブジェクトは別のクラスター上にある可能性もあります。その名前をステップ 6 に戻してください。

上位のオペレーターだけについて、分布を確認します: オペレーターの偏り。

max_worker_ratio がワーカー数に近づくほど高くなる場合、1 つのワーカーがそのオペレーターを処理しており、データフローはそのワーカーの速度で実行されています。そのオペレーターを挙げたうえで、それが空のキーを持つ Arrange かどうかを確認してください。キーが空だと、すべてのレコードが 1 つのワーカーに送られます。これはクロス結合、または述語がすべて不等式である結合で発生します。処理を分散するには、結合に少なくとも 1 つの等価条件が必要です。求められた場合は、ホットキーの特徴を説明してください。

コストの高いオペレーターの比率が 1 に近い場合、偏りではなく、プラン自体のコストが高いことを意味します。結合順序と、さらに下流へ押し下げられるフィルターや射影を確認してください。物理プランの Source セクションには、project、filter、pushdown が表示されます。

オペレーターの意味:オペレーターの読み方。

ステップ 8:オペレーターを SQL に対応付ける

  1. コストの高いオペレーターとその lir_id の値は、ステップ 7 ですでに取得しています。
  2. SQL を所有するオブジェクトを特定します。マテリアライズドビューの場合は、そのオブジェクト自体です。インデックスの場合は、mz_indexes.on_id を使ってインデックス対象を特定します。マテリアライズドビューに対するインデックスは、そのビューの遅延を引き継ぐため、代わりにマテリアライズドビューを分析します。一方、通常のビューに対するインデックスは、そのビューの本体全体を自身のデータフローに含みます。
  3. データフローにインライン化されているビューを特定します。通常のビューには独自のデータフローがないため、その本体はそれを使用するオブジェクトの内部に構築され、コストの高いオペレーターがそこから生じている可能性があります。mz_object_dependencies を再帰的にたどり、型が view のすべての依存関係を集めます。マテリアライズドビュー、テーブル、ソースは独自のデータフローを持つ境界です。クエリはリファレンスにあります。
  4. EXPLAIN PHYSICAL PLAN WITH (node identifiers) AS TEXT FOR ... を実行します。各ノードには // { node_id: LirId(N) } があり、ステップ 1 で取得した ID と一致します。また、列名、結合述語、グループキーも確認できます。
  5. ステップ 2 と 3 で取得した定義を SHOW CREATE MATERIALIZED VIEW または SHOW CREATE VIEW で読み、プランノードの元になった句を見つけます。

クエリと実例: references/dataflow-analysis.md。

ステップ 9:報告する

すべての項目を埋めてください。「None」も有効な値であり、省略するより有用です。

**Culprit:** <fully qualified name> on cluster <cluster>, replica <replica>
**Classification:** unhealthy source or sink | recovered peak, nothing behind now
| still hydrating | starved by another dataflow | worker skew | expensive plan |
undersized replica | lag enters at the root | nothing behind | inconclusive
**Evidence:**
- Lag: <object> at <lag>, history <shape> over <samples> minutes
- Attribution: <hop chain, with the local_lag of the hop that owns it>
- Replica: <cpu_percent>, <heap_percent>, top dataflow <percent of total>
**Expensive operator:** <operator> at <percent_of_dataflow>, worker ratio <ratio>
**SQL:** <clause>, in <fully qualified view name>, inlined into <dataflow name>
**Ruled out:** <what was checked and found healthy>
**Unexplained:** <what the evidence does not account for>

句、それを含むビュー、データフローをそれぞれ別に記載してください。異なる場合は、修正すべきデータフローと編集すべきファイルの両方が読者に伝わるようにします。

報告書が成果物です。改善策は別途依頼してください。

コメント