Back to Blog
ArticleApril 23, 20268分

私のパイプラインは回復力があると思っていたが、これらの5つの質問をするまでそうではなかった

回復力とは「動作すること」ではなく、「周囲がすべて壊れても動作すること」です。その違いを知る方法はこちら。

私のパイプラインは回復力があると思っていたが、これらの5つの質問をするまでそうではなかった

Andrew Tanによる

レジリエンスとは「動作する」ことではなく、「周囲がすべて壊れたときに動作する」ことです。その違いを知る方法はこちらです。


災害になるはずだった移行

6か月前、私がアドバイスしているSaaS企業が、主要なPostgreSQLインスタンスを新しいクラウドリージョンに移行することを決定しました。計画はシンプルでした。レプリカを立ち上げ、昇格させ、接続文字列を更新し、すべてが動作することを確認する。予想されるダウンタイムは15分。

実際に起こったことはもっと興味深いものでした。レプリカの昇格は成功しました。接続文字列の更新も成功しました。しかし、顧客分析ダッシュボードにデータを供給するデータパイプライン — 18か月間問題なく稼働していたパイプライン — が即座にナンセンスなデータを生成し始めました。エラーではありません。ナンセンスです。行数は問題ありませんでした。スキーマも無傷でした。しかし、コンバージョンファネルのメトリクスが12%ずれており、パイプラインがすべての監視ダッシュボードで「緑色」だったため、誰も4時間気づきませんでした。

根本原因は?パイプラインには、本来データパスの一部であるべきでないリードレプリカへの隠れた依存関係がありました。誰かが2年前にパフォーマンス最適化としてそれを追加し、ドキュメント化していませんでした。古いリージョンがオフラインになったとき、その最適化は単一障害点となりました。パイプラインはクラッシュしませんでした。ただ静かに古いデータを消費し、ゴミを生成しただけです。

これが私がレジリエンスとは稼働時間ではないと言う理由です。そのパイプラインは99.9%の稼働時間を持っていました。チームが追跡していたすべてのメトリクスによれば、技術的には「レジリエント」でした。しかし、実際に何かがうまくいかなくなったときに重要な方法ではレジリエントではありませんでした。

その事件以来、私はどのパイプラインも本番準備ができていると呼ぶ前に5つの質問をするようになりました。これらは理論的なアーキテクチャレビューの質問ではありません。「通常の条件で動作する」と「世界が燃えているときに動作する」の間のギャップを明らかにするものです。


質問1: このコンポーネントが失敗した場合、他に何が壊れるか?

ほとんどのデータパイプラインはクリスマスライトのように構築されています。1つの電球が切れると、全体が暗くなります。エンジニアが不注意だからではなく、依存関係が時間とともに自然に蓄積されるからです。パイプラインはシンプルに始まります。それから参照データが必要になり、共有キャッシュから読み取ります。それからエンリッチメントが必要になり、内部APIを呼び出します。それから集約が必要になり、他の3つのパイプラインも使用する状態ストアに書き込みます。誰もアーキテクチャ図を描いていないうちに、すべてのコンポーネントが負荷を支えるシステムを構築してしまい、何も単独で失敗しません。

私はこれを爆発半径の問題と呼びます。レジリエントなパイプラインは明示的な失敗ドメインを持っています。1つの部分が壊れると、損害は封じ込められます。チームは特定のコンポーネントについてアラートを受け取ります。システムの残りは動作を続け、場合によっては劣化モードで動作しますが、連鎖的な失敗はありません。

クリスマスライトの問題は、特に何年もかけて進化したバッチパイプラインで一般的です。新しい要件が既存のフローに取り付けられるたびに、全体を書き直すのはリスクがあると感じます。その結果、失敗モードが常に全体の失敗であるパイプラインが生まれます。部分的な成功はありません。優雅な劣化もありません。ただの緑か赤です。

これを修正するには、最初から分離を設計する必要があります。取り込みを変換から提供から分離します。状態のために境界付きコンテキストを使用します。すべての依存関係が失敗すると仮定し、もしそうなった場合、パイプラインの残りが機能を減らしても続行できるかどうかを尋ねます。答えがノーなら、レジリエンスはありません。楽観主義があります。


質問2: このパイプラインは人間なしで復旧できるか?

午前3時のテストが重要です。パイプラインが午前3時に失敗します。オンコールエンジニアがページングされます。その後何が起こりますか?

ほとんどの組織では、眠そうな人間がラップトップを開き、ログを読み、ジョブを再起動し、再び起こらないことを願ってベッドに戻ります。これは復旧ではありません。これは遅延です。パイプラインは20分、1時間、時にはそれ以上ダウンしています。データは古くなっています。下流のシステムは昨日の入力に基づいて結果を生成しています。

レジリエントなパイプラインは自動的に復旧します。すべての失敗に対してではありません — 一部の問題は本当に人間の判断が必要です — しかし予測可能なものに対しては。メモリ不足エラーは、調整されたリソース制限でのリトライをトリガーするべきです。一時的なネットワークの問題は、即時の失敗ではなく指数バックオフをトリガーするべきです。スキーマの不一致は、悪いレコードをデッドレターキューにルーティングし、有効なものの処理を続行するべきです。

夜中に眠れるチームは自己修復に投資しています。彼らは失敗モードを分類し、創造性を必要としないものに対する応答を自動化しています。午前3時のページはまれになり、システムが予測可能な問題を自分で処理します。

これは単にリトライを追加する以上のものを必要とします。リトライセーフにパイプラインを設計する必要があります。冪等操作。決定論的な出力。「一時的な問題で失敗した」と「入力データが根本的に間違っているために失敗した」の間の明確な分離。最初のカテゴリは自分で修復するべきです。2番目のカテゴリは大声で具体的に失敗し、悪いデータを営業時間中に人間が検査できる場所にルーティングするべきです。


質問3: 失敗したとき、実際に何が起こったかを知っていますか?

私が何度も見たシナリオがあります。パイプラインが失敗します。ログには「ワーカースレッドでの例外」と書かれています。監視ダッシュボードには赤い点が表示されます。アラートには「ジョブが失敗しました」と書かれています。そしてページングされたエンジニアは、パイプラインが壊れたときに何をしていたのかという基本的な質問に答えるために次の1時間を費やします。

ほとんどの監視は何かが失敗したことを教えてくれます。なぜかは教えてくれません。パイプラインが何を処理していたのか、どの状態にあったのか、下流の影響が何であるかを教えてくれません。患者が病気であることはわかります。症状、診断、治療法はわかりません。

レジリエントなパイプラインは観測可能です。単に監視されているだけではなく、観測可能です。この違いは重要です。監視はジョブが終了したかどうかを確認します。観測可能性は、終了しなかったときに何が起こったのかを再構築することを可能にします。すべてのステージを通じてレコードを追跡する分散トレーシング。コンテキストを含む構造化ログ、イベントだけではありません。プロセスの健康だけでなく、データの健康を露出するメトリクス。

私が一緒に働いたあるチームは、すべてを変えたシンプルなチェックを追加しました:彼らはすべての変換ステージで入力レコードIDをログに記録し始めました。何かが壊れたとき、彼らはパイプラインを通じて正確なレコードを追跡し、どのステージがエラーを生成したのかを見ることができました。その変更前は、デバッグに数時間かかっていました。変更後は数分で済みました。パイプライン自体はより信頼性が高くなかった。しかし、失敗に対するシステムの応答が非常に速くなり、実質的なダウンタイムが80%減少しました。

デバッグプロセスがサーバーにSSHして非構造化ログファイルをgrepすることを含んでいる場合、観測可能性はありません。考古学があります。そして考古学は午前3時には高価です。


質問4: すべてが失敗したときにデータの整合性を保護しますか?

私が夜も眠れない特別なカテゴリの失敗があります。それは全く失敗しないパイプラインです。それは動作します。それは完了します。それは成功を報告します。そして間違ったデータを生成します。

これはクラッシュよりも悪いです。クラッシュは明らかです。間違ったデータは微妙です。それはシステムを通じて伝播します。それは意思決定に使用されます。誰かが数字が現実と一致しないことに気づくまでに数日または数週間かかるかもしれません。その時点で、悪いメトリクスに基づいて機能を出荷し、間違った数字でレポートを送信し、パイプラインのどこかで静かに破損したデータを使用して戦略的な決定を下しています。

レジリエントなパイプラインは、データの整合性を後から考えるのではなく、第一級の懸念事項として扱います。彼らは処理前に入力を検証します。ステージ境界で不変条件をチェックします。入力と出力が一致することを確認するためのチェックサムやカウントを維持します。そして検証が失敗したとき、彼らはパイプラインを大声で、具体的に、問題を診断するのに十分なコンテキストで失敗させます。

ここで私が使う言葉は「フェイルクローズド」です。フェイルクローズドなパイプラインは、正確性を保証できないときに停止します。フェイルオープンなパイプラインは進み続け、誰も気づかないことを願います。ほとんどのパイプラインはデフォルトでフェイルオープンです。なぜなら、それが最も抵抗が少ない道だからです。フェイルクローズドにするためには明示的な設計決定が必要です。

1つの実用的なパターン:すべてのバッチパイプラインの終わりに調整ステージを追加します。入力レコードを数えます。出力レコードを数えます。ソースと宛先の間でキーとなるメトリックの合計が一致することを確認します。これらのチェックは静かな失敗をキャッチします — ドロップされたレコード、重複した書き込み、有効なデータを静かにフィルタリングする結合条件。これらは無料ではありません。レイテンシーを追加します。しかし、見えないデータの破損を見える、実行可能なエラーに変えます。


質問5: 壊れたときに何が起こるかをテストしましたか?

これはレジリエンスについて話すチームと実際に持っているチームを分ける質問です。制御された環境で意図的にパイプラインを壊し、何が起こるかを観察しましたか?

ほとんどのチームはしていません。彼らはハッピーパスを徹底的にテストします。正しい入力が正しい出力を生成することを確認します。予想されるボリュームでのパフォーマンスを確認するために負荷テストを実行します。そして予期しないことが起こらないことを願って本番にデプロイします。

本当にレジリエントなパイプラインを構築するチームは失敗注入を実践します。ジョブの途中でデータベース接続を切断します。APIコールでレイテンシースパイクを導入します。入力レコードを破損させ、それらが正しく処理されることを確認します。割り当てられたメモリの半分でパイプラインを実行し、突然のクラッシュではなく優雅な劣化を観察します。

これは単なるカオスエンジニアリングのためではありません。あなたのレジリエンスメカニズムが実際に機能することを検証するためです。トリガーしたことのないサーキットブレーカーは壊れないかもしれません。テストしたことのないリトライポリシーは無限にリトライするかもしれません。検査したことのないデッドレターキューは、すべての不正なレコードを静かにドロップしているかもしれません。

洗練されたカオスエンジニアリングプラットフォームは必要ありません。必要なのは、次の質問をする規律です:この依存関係がダウンした場合、何が起こりますか?この入力が不正な場合、何が起こりますか?このジョブが誤って2回実行された場合、何が起こりますか?そしてそれらのシナリオを実際にテストし、それらが大丈夫だと仮定しないことです。


結論

レジリエンスはパイプラインが構築された後に追加する機能ではありません。それは特定の設計決定から生じる特性です:爆発半径を制限する分離境界、予測可能な失敗を処理する自己修復メカニズム、デバッグを迅速にする観測可能性、静かな破損を防ぐ整合性チェック、仮定を検証するテストされた失敗モード。

私が以前に説明したデータベース移行を生き延びたパイプライン?それは運が良かったのではありません。それはこれらの5つの質問をし、それに対する明示的な答えをアーキテクチャに組み込んだチームによって設計されました。隠れた依存関係が失敗したとき、パイプラインは静かにゴミを生成しませんでした。それはフェイルクローズドし、具体的にアラートし、影響を受けたレコードを人間のレビュキューにルーティングしました。損害は1つのダッシュボードで4時間の遅延に限定されました。下流の破損はありません。間違ったデータに基づく悪い決定はありません。午前3時の緊急事態もありません。

それがレジリエンスの姿です。完璧な稼働時間ではありません。無限のスケーラビリティでもありません。ただ何かが壊れたとき — そして何かは常に壊れます — システムが予測可能に振る舞い、損害を封じ込め、何が起こったのかを正確に教えてくれるという自信です。


次に何をするか

今あなた自身のパイプラインを見ているなら、1つの質問から始めてください:このパイプラインが依存している5つのものを名前で挙げられ、それぞれが失敗したときに何が起こるかを知っていますか?それに答えられないなら、あなたの出発点が見つかりました。

1つの依存関係を選びます。その失敗モードをテストします。何が起こるかを観察します。壊れたものを修正します。繰り返します。

レジリエンスは目的地ではありません。それは実践です。そしてそれを実践するチームが夜も眠れるチームです。

ストリーミングパイプラインを構築するチーム向けに、layline.ioは組み込みの分離境界、正確に1回の処理保証、失敗が発生したときに追跡を容易にするビジュアルデバッグを提供します — なぜなら失敗は発生し、重要なのはシステムがどのように応答するかです。

Community Editionを試す →


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

Share:

Enjoyed this article?

Subscribe to get more insights delivered to your inbox.