Databricks Certified Data Engineer Associate 教科書
第6章 トラブルシューティング・監視・最適化(Troubleshooting, Monitoring, and Optimization, 10%)
🎯 この節の学習目標
本番のパイプラインで問題が起きるとき、最初に気づく症状はたいてい「ジョブが失敗した」か「ジョブがいつもより遅い」のどちらかです。どちらの場合も、いきなり Spark UI やログの深掘りに飛び込むのではなく、まず Lakeflow Jobs の実行履歴で「いつから・どのタスクで・どの程度」異常が出ているのかを絞り込むのが定石です。全体像を掴んでから詳細に降りることで、無関係な箇所を調べる時間を省けます。
Lakeflow Jobs のジョブ詳細画面には、過去の実行(run)が一覧・可視化される実行履歴(run history)ビューがあります。ここでは各実行の開始時刻・実行時間(duration)・ステータス(成功/失敗)・起動種別(スケジュール/手動/API)などを確認でき、実行時間は棒グラフとして時系列に並べて表示されます。
📝 試験のポイント
「ジョブの実行時間が最近長くなっていないかを確認したい」「パフォーマンスが劣化し始めた時期を特定したい」という要件に対する第一の答えは、ジョブの実行履歴ビューで実行時間のトレンドを過去のベースラインと比較することです。個々の実行のログを開く前に、まず履歴の傾向を見る、という順序を押さえておきましょう。
パフォーマンス劣化の検出で重要なのは、「今日の実行が30分だった」という絶対値ではなく、「普段は10分で終わる処理が30分かかっている」というベースライン(平常時の水準)との比較です。実行履歴ビューを使った典型的な確認手順は次のとおりです。
| 手順 | 見るもの | 判断できること |
|---|---|---|
| 1. 実行時間の推移を見る | 実行履歴の duration グラフ | 「徐々に遅くなっている(データ量増加・小ファイル蓄積などの慢性要因)」か「ある日を境に急に遅くなった(コード変更・クラスタ構成変更・データの偏りなどの急性要因)」かを切り分けられる |
| 2. 遅い実行を開く | タスクごとの実行時間の内訳 | ジョブ全体ではなくどのタスクが遅くなったのかを特定できる |
| 3. 正常だった実行と比べる | 同じタスクの過去の実行時間 | 劣化がそのタスク固有か、複数タスクに及ぶか(クラスタ起因の可能性)を判断できる |
💡 具体例:夜間ETLジョブの劣化検出
毎晩実行される ETL ジョブの SLA は「午前6時までに完了」だとします。実行履歴を見ると、3か月前は45分だった実行時間が、直近では緩やかに右肩上がりで80分に達していました。急激な変化点がないため、コード変更よりもデータ量の増加や小ファイルの蓄積といった慢性的な要因が疑われます。タスク別の内訳を見ると、集計タスクだけが伸びており、他のタスクは横ばいでした。ここまで絞り込めたら、次のステップは該当タスクの Spark UI でボトルネックの種類(スキュー・シャッフル・スピル)を確かめることです(6-2 で詳述)。
ジョブ実行と、その中の各タスクには、それぞれステータスが付きます。代表的なものを整理します。
| ステータス | 意味 | 対応 |
|---|---|---|
| Succeeded(成功) | 実行が正常に完了した | 実行時間がベースラインから外れていないかだけ確認する |
| Failed(失敗) | タスクがエラーで終了した | 失敗したタスクの出力・エラーメッセージ、ドライバーログを確認する |
| Skipped(スキップ) | 依存する上流タスクが失敗・未完了のため実行されなかった | スキップされたタスク自体には問題がない。上流をたどって最初に失敗したタスクを探す |
| Cancelled(キャンセル) | 手動キャンセル、またはタイムアウト等により中断された | 誰が・何が(タイムアウト設定など)キャンセルしたのかを実行の詳細で確認する |
| Running / Pending | 実行中/実行待ち(クラスタ起動待ちを含む) | Pending が長い場合はクラスタ起動の問題(6-4)を疑う |
複数タスクからなるジョブは、タスク間の依存関係が DAG(有向非巡回グラフ)として可視化されます。実行の詳細画面ではこの DAG 上に各タスクのステータスが色分けされて表示されるため、障害調査では次の読み方をします。
💡 具体例:Skippedの海から失敗源を探す
10タスク構成のジョブが失敗し、実行結果を見ると7つのタスクが Skipped でした。慌てて Skipped のタスクを調べても手がかりはありません。DAG ビューで上流をたどると、bronze 層の取り込みタスク1つが Failed で、その下流がすべて Skipped になっていたと分かりました。取り込みタスクのエラーメッセージを見ると、ソースファイルのスキーマ変更が原因でした。修正後、repair run で失敗タスク以降のみを再実行し、成功済みの前段タスクは再計算せずに復旧できました。
問題が起きてから履歴を見るのではなく、起きた瞬間に知らせてもらうのが監視の基本です。Lakeflow Jobs では、ジョブ単位・タスク単位で通知を設定できます。
| 通知の種類 | 発火条件 | 主な用途 |
|---|---|---|
| 失敗時(on failure) | ジョブまたはタスクが失敗した | 障害の即時検知。最低限これは設定する |
| 開始時/成功時(on start / on success) | 実行の開始/正常完了 | 下流の運用担当への連絡、完了確認 |
| 実行時間の警告(duration warning) | 実行時間が設定したしきい値を超えた | SLA 違反の予兆検知。「失敗はしていないが遅すぎる」を捕まえる |
| 実行時間の上限(timeout) | 設定した上限時間を超えた実行を強制終了 | ハングした実行がクラスタコストを垂れ流すのを防ぐ |
通知の宛先にはメールのほか、Webhook 経由でチャットツールや監視システムを指定できます。ここで大切なのは、duration warning は「通知するだけ」で実行は継続し、timeout は「実行を打ち切る」という違いです。SLA が厳しいジョブには、しきい値を段階的に設定(例:警告=平常時の1.5倍、タイムアウト=3倍)しておくと、劣化の予兆と暴走の両方に対処できます。
📝 試験のポイント
「ジョブが失敗したらすぐチームに知らせたい」→ 失敗時通知。「ジョブが所定時間より長くかかっていたら知りたい(ただし止めたくはない)」→ duration warning。「一定時間を超えた実行は打ち切りたい」→ timeout。この3つの使い分けを選択肢の文面から判別できるようにしておきましょう。
この節の内容を「ジョブが遅くなった」という症状に対する診断フローとしてまとめます。ジョブレベルの監視でどこが遅いかを特定し、タスクレベルの深掘りは Spark UI(6-2)に引き継ぐ、という役割分担です。
図:ジョブ遅延の診断フロー(全体から詳細へ絞り込む)
✅ この節のまとめ
問1. 毎晩実行されるジョブについて「最近、実行時間が長くなってきた気がする」という報告を受けた。劣化の有無と始まった時期を確認する方法として最も適切なのはどれか。
正解:B
「劣化の有無」と「始まった時期」はどちらもトレンドの問題なので、実行履歴で時系列の実行時間をベースラインと比較するのが正解です。Aはエラーが出ていない性能劣化には無力で、時期の特定もできません。Cは原因を特定せずに対処しており、コスト増だけで解決しない可能性があります。Dは1回分の測定にすぎず、傾向も時期も分かりません。
問2. 10タスク構成のジョブが失敗した。実行結果を見ると、タスクの多くが「Skipped」と表示されている。原因特定のために最初にとるべき行動はどれか。
正解:B
Skipped は「依存する上流タスクが失敗したため実行されなかった」ことを示す結果であり、原因はその上流にあります。DAG をたどって最初に失敗したタスクを見つけ、そのエラーメッセージを読むのが最短経路です。Aは原因のないタスクを調べるため時間の無駄です。Cは原因不明のまま再実行しても同じ失敗を繰り返す可能性が高く、計算コストも無駄になります。Dはクラスタ起動失敗が疑われる場合の手段で、タスク失敗の一次調査としては遠回りです。
問3. SLA上、午前6時までに完了すべきジョブがある。「失敗してはいないが、実行時間が通常より大幅に長くなっている」状況を、実行を止めずに早期検知したい。設定すべきものはどれか。
正解:B
要件は「失敗ではなく遅延を、実行を継続したまま検知する」ことなので、しきい値超過で通知だけを行う duration warning が該当します。Aは失敗しない限り発火しないため、この症状を捕まえられません。Cのtimeout は実行を強制終了してしまうため「止めずに検知」という要件に反します。Dは通知の削減であり、検知には寄与しません。
問4. 複数タスクのジョブで中盤のタスクが失敗した。前半のタスクは成功しており、その処理には長い時間がかかっている。原因を修正した後、最も効率よくジョブを完了させる方法はどれか。
正解:B
repair run は成功済みタスクの結果を保持したまま、失敗したタスクとその下流だけを再実行する機能です。前半の長時間処理を繰り返さずに済むため、復旧時間と計算コストの両方を節約できます。Aは成功済みの処理まで再計算するため非効率です。Cはジョブ定義の複製で管理が複雑になるうえ、依存関係が失われます。Dは必要な処理を実行しないままジョブを「成功」させてしまい、データの欠損につながります。