Back to Blog
ArticleApril 6, 20267分

なぜほとんどのデータパイプラインは午前3時に失敗するのか(そして失敗しないものを構築する方法)

夜中に本番データパイプラインが壊れる本当の理由と、それを防ぐエンジニアリングプラクティス

なぜほとんどのデータパイプラインは午前3時に失敗するのか(そして失敗しないものを構築する方法)

Andrew Tanによる

夜中にプロダクションデータパイプラインが停止する本当の理由と、それを防ぐエンジニアリングプラクティス


ページャーが鳴る

午前3時17分。あなたの電話がナイトスタンドから振動して落ちます。手探りで電話を取り、明るさに目を細めながら、以前見たことのあるメッセージを確認します:「データパイプラインが失敗しました。最後の成功した実行:14時間前。」

次に何が起こるかはわかっています。次の2時間をSlackスレッドで過ごし、意味不明なログを見ながら、これが先週の失敗と同じものか、それとも新しいものかを突き止めようとします。午前6時までには、回避策を実行しています。午前9時までには、チームに「今のところ対処済み」と伝えます。そして来月には、また同じことを繰り返します。

私もその経験があります。認めたくないほど何度も。そして、何年もデータインフラを構築し、同じサイクルを経験したチームと話をした後、気づいたことがあります:午前3時の失敗はランダムではありません。パターンに従っています。そして、そのほとんどは防ぐことができます。

なぜ午前3時なのか?

その時間に特別なものはありません。しかし、午前3時に存在する条件には予測可能なものがあります:

人間の要因が最低です。 パイプラインを構築したエンジニアは眠っています。パイプラインの癖を知っているオペレーターはシフト外です。誰かの頭の中にある組織的な知識にはアクセスできません。残されているのは、6か月前に正確だったドキュメントと、「誰でも知っている」手順を省略したランブックです。

データ量がピークに達します。 グローバルなユーザーベースでは、あなたのタイムゾーンでの「夜」は他の場所では「昼」です。その午前3時の失敗?それはおそらくアジアやヨーロッパのユーザーが最も活発なときに起こっています。正午に1分間に10,000イベントを処理していたパイプラインが、突然50,000イベントに溺れています。

依存関係が連鎖的に失敗します。 あなたのパイプラインは孤立して存在しているわけではありません。データベースから引き出し、独自のメンテナンスウィンドウを持っています。APIに書き込み、レート制限があります。オフピーク時間に更新をデプロイするサービスに依存しています。午前3時に1つのリンクが壊れると、その波及効果が誰も気づく前にパイプラインに影響を与えます。

バッチジョブが積み重なります。 午前2時のETLジョブは、問題なく実行されますが、ある日突然、そうではなくなります。おそらくソースシステムが遅かったのでしょう。おそらくデータ量が多かったのでしょう。おそらくネットワークの障害が20分のレイテンシーを追加しました。突然、午前2時のジョブが午前3時にまだ実行されており、ダッシュボードが依存している午前3時のジョブが開始され、データの半分が破損する競合状態を作り出します。

午前3時の失敗は単一のバグではありません。それは、個別には問題ない複数の設計決定が重なり、壊滅的な結果をもたらすものです。

夜間の失敗を引き起こす5つのパターン

これらのインシデントをデバッグするチームを何度も見てきた結果、5つの繰り返しパターンを特定しました:

1. サイレントフェイル

ジョブは「成功」と報告しますが、ゴミデータを生成しました。パイプラインがクラッシュしなかったため、アラートは発動しませんでした。朝になって誰かが昨日の収益数字が電話番号のように見える理由を尋ねるまで、気づきません。

夜に起こる理由: 昼間の失敗は、ダッシュボードを見て異常を察知する人間によって捕捉されます。夜間の失敗は朝まで待ちます。

修正方法: 検証ゲート。すべてのパイプラインには、出力が期待に沿っていない場合にジョブを失敗させる明示的なデータ品質チェックが必要です。期待範囲内の行数。しきい値以下のヌル率。参照整合性チェック。データが間違っている場合、パイプラインは静かに成功するのではなく、大きな音を立てて失敗するべきです。

2. リソース枯渇

パイプラインはステージングで問題なく動作しました。数か月間、プロダクションでも問題なく動作しました。しかしある日、データ量が知らなかったしきい値に達し、突然メモリ不足、ディスク不足、またはAPIクォータ不足になりました。

夜に起こる理由: 多くのリソース制限は、突然ではなく徐々に厳しくなります。メモリリークが蓄積します。ログファイルが成長します。テンポラリテーブルがいっぱいになります。午前3時のジョブがついに壁にぶつかるのです。

修正方法: リソース監視とプロアクティブな制限。ジョブが完了したかどうかだけでなく、メモリ使用量の傾向、ディスクスペースの推移、APIクォータの消費を監視します。70%のしきい値でアラートを設定し、100%ではありません。そして、優雅な劣化を設計します:すべてを処理できない場合、最も重要なサブセットを処理できますか?

3. 外部依存関係のタイムアウト

パイプラインはAPIを呼び出します。通常は200msで応答しますが、今夜は30秒かかっています。デフォルトのタイムアウトは60秒なので、ジョブはすぐに失敗せず、ただ遅くなります。タイムアウトするまでに、他のジョブが必要とするリソースのロックを保持しています。

夜に起こる理由: サードパーティサービスはオフピーク時間にメンテナンスを行います。ネットワークパスが再ルーティングされます。DNSが伝播します。あなたが制御できないインフラが警告なしに変わります。

修正方法: サーキットブレーカーと現実に合わせたタイムアウト。99%のAPIコールが5秒以内に完了する場合、タイムアウトを60秒ではなく10秒に設定します。依存関係が苦しんでいるときにすぐに失敗するサーキットブレーカーを実装します。指数バックオフを使用したリトライロジックを設計し、苦しんでいるサービスをすぐに叩かないようにします。

4. 状態の不一致

パイプラインはイベントを順番に処理します。しかし今夜、イベントが順不同で到着しました。あるいは重複したイベントが到着しました。あるいは、互いに意味をなさないタイムスタンプを持つイベントが到着しました。状態を持つ集計がナンセンスを生成したのは、イベントの順序に関する仮定が破られたからです。

夜に起こる理由: 分散システムは最終的に整合性を保ちます。ネットワークパーティションが発生します。メッセージキューは負荷がかかると順序を変更します。あなたが仮定した不変条件 — 「イベントは順番に到着する」「イベントは正確に一度到着する」— は、あなたのインフラが実際には提供していない保証です。

修正方法: 防御的な状態管理。イベントタイム処理を使用し、処理時間ではなく、順不同のイベントをウォーターマークで処理します。少なくとも一度のセマンティクスを設計し、集計を冪等にします。イベントが遅れる、重複する、または欠落することを想定し、それを優雅に処理します。

5. 設定のドリフト

パイプラインは昨日動作しました。コードには何も変更がありません。しかし、誰かが環境変数を更新しました。あるいは資格情報をローテーションしました。あるいはデータベーススキーマを更新せずに変更しました。コードは同じですが、それが実行される世界が変わりました。

夜に起こる理由: インフラの変更はしばしばメンテナンスウィンドウ中にデプロイされます。スキーマの移行はオフピーク時間に実行されます。資格情報のローテーションはスケジュールに従って行われます。午前3時のジョブが新しい世界に最初に遭遇します。

修正方法: コードとしての設定、コードとしてテスト。すべての環境変数、すべてのシークレット参照、すべてのスキーマ仮定は、バージョン管理され、検証されるべきです。インフラの変更後にパイプラインを「ドライラン」モードで実行します。スキーマのドリフトにアラートを出します。設定の変更をコードの変更と同じ厳密さで扱います。

マインドセットのシフト:「失敗を処理する」から「失敗を防ぐ」へ

私が知っているほとんどのデータチームは、リアクティブモードで動作しています。パイプラインが失敗します。彼らはそれを修正します。何が起こったかを文書化します。そして次に進みます。その後、少し異なる理由で再び失敗し、サイクルが繰り返されます。

午前3時にページを受け取らないチームは、異なるアプローチを取っています。彼らは失敗ドメインと影響範囲を考えます。彼らは尋ねます:「このコンポーネントが失敗した場合、他に何が壊れるのか?」彼らは完璧な信頼性よりも優雅な劣化を設計します。

それが実際にどのように見えるかは次のとおりです:

失敗だけでなく成功パスもテストします。 テストスイートには、依存関係がタイムアウトする、データが不正である、リソースが枯渇するシナリオを含めるべきです。ハッピーパスだけをテストしている場合、プロダクションをテストしているわけではありません。

モニタリングよりもオブザーバビリティ。 モニタリングはジョブが失敗したことを教えてくれます。オブザーバビリティはその理由を教えてくれます。イベントをパイプライン全体で追跡するトレーシングに投資します。イベントだけでなくコンテキストをログに記録します。データ品質の健康状態を示すダッシュボードを構築し、ジョブの完了だけを示すのではありません。

データパイプラインのためのカオスエンジニアリング。 パイプラインを意図的に制御された方法で壊していない場合、それがどのように失敗するかを知りません。データベース接続を切断し、レイテンシーを導入し、入力データを破損させるドリルを実行します。失敗モードを学び、それらがあなたを学ぶ前に。

修正できる人にエスカレートするオンコール。 午前3時にページを受け取る人は、問題を実際に修正できる人であるべきです。ジョブを再起動して希望するだけではありません。オンコールのローテーションがあまりにジュニアである場合、実際の修正を朝まで遅らせているだけです。

夜を通して眠るパイプラインの構築

レジリエントなデータパイプラインには共通の特性があります。それらは魔法ではありません — 特定のパターンで設計されています:

どこでも冪等性。 同じジョブを2回実行すると、1回実行した場合と同じ結果が得られるべきです。これにより、リトライが安全になり、回復が自動化されます。

Backpressure処理。 下流システムが追いつけない場合、パイプラインはクラッシュしたりデータをドロップしたりせず、スローダウンするべきです。負荷を優雅に減らすべきであり、壊滅的に減らすべきではありません。

制限された状態。 状態を持つ操作には制限があるべきです。TTLを持つウィンドウ集計。削除ポリシーを持つ状態ストア。無制限の状態が無制限の問題にならないようにします。

明示的な契約。 パイプラインの境界でスキーマを定義し、検証します。不正なデータを早期に拒否します。仮定が破られたときにすぐに失敗します。

機能する運用ランブック。 すべてのアラートにはランブックがあるべきです。すべてのランブックはテストされるべきです。ランブックが「ログを確認する」と言う場合、どのログを、何を探すべきか、見つけたときに何をすべきかを指定します。

結論

午前3時のページは避けられないものではありません。それはスループットをレジリエンスよりも優先し、完了を正確性よりも優先し、機能の速度を運用の成熟度よりも優先した設計選択の症状です。

夜を通して眠るチームは運が良いわけではありません。彼らはエラーハンドリング、検証、オブザーバビリティという地味な作業に投資しています。彼らは失敗が起こることを受け入れ、それを優雅に処理するシステムを設計しています。

ユーザーはあなたのパイプラインが賢いかどうかは気にしません。彼らが必要なときにデータが正しいかどうかを気にします。それを目指して構築してください。


次に何をするか

午前3時のページにうんざりしているなら、1つの変更から始めてください:最も重要なパイプラインに1つの検証ゲートを追加します。行数を確認します。ヌル率を検証します。主要なビジネスメトリックを検証します。データが間違っている場合、パイプラインを失敗させます。

それは完全な解決策ではありませんが、始まりです。そして、データ品質の問題をユーザーに届く前にキャッチする安心感を感じたら、次の安全策を追加するモチベーションが生まれるでしょう。

ストリーミングパイプラインを構築するデータエンジニアリングチーム向けに、layline.ioは組み込みのBackpressure処理、exactly-onceセマンティクス、問題が発生したときに何が起こっているのかを理解しやすくするビジュアルデバッグを提供します — それが午後3時であれ午前3時であれ。Community Editionは無料で試すことができます。

Community Editionを試す →


Andrew Tanはシリアルアントレプレナーであり、layline.ioの創設者であり、バッチとリアルタイムの両方のワークロードをスケールで処理するエンタープライズデータ処理インフラを構築しています。

Share:

Enjoyed this article?

Subscribe to get more insights delivered to your inbox.