目次を開く
「成功」が嘘をつくとき — PaaS 運用で繰り返し踏んだサイレント障害

「成功」が嘘をつくとき — PaaS 運用で繰り返し踏んだサイレント障害

エラーを出さないバグが、いちばん危ない

前回、さくらのクラウドで PaaS を作るときの認証情報 3 種の使い分けを書いた。その記事で一度触れた話がある。「認証が通った」は「意図した身分で認証が通った」を意味しない、というものだ。署名さえ正しければ、別人の ID でも認証は成立してしまう。処理が成功を返したことと、処理が意図どおりに効いたことは、別のことである。

EastCloud ではさくらのクラウド上でアプリケーション実行基盤(PaaS)を開発している。その運用を続けるうちに分かってきたことがある。いちばん危険なバグは、エラーを吐くバグではない。成功を返しながら、実際には何も起きていないバグである。

エラーは、少なくとも気づける。ログに赤い行が出て、アラートが鳴り、誰かが調べ始める。だが「成功を返しながら動いていない」バグは、どの監視にも引っかからない。すべてのレコードが succeeded だからだ。これを本稿では サイレント障害(静かに壊れていて、しかし失敗の signal を一切出さない状態)と呼ぶ。

処理が成功を返し記録され監視も静かだが、本当に効いたかは検証されていない。試みの成功と効果の成功の隙間にサイレント障害が棲む
図1:成功という signal は「試みた」ことの報告であって、「効いた」ことの報告ではない

以下は、運用の中で繰り返し踏んだサイレント障害を、構造ごとに 4 つに分けたものである。個別のシステム名や数字は本質ではないので省く。大事なのは、どれも同じ一点から来ているという事実のほうだ。


パターン 1:成功を返し続ける復旧ループ

障害から自動で立ち直る仕組みを入れたとする。あるコンポーネントが落ちたら、作り直す。作り直しが済んだら「成功」を記録する。素直な設計に思える。

ところが、作り直しの処理は成功を返すのに、作り直したはずの状態が実際には回復しない、という状況が起こり得る。たとえば作り直しの API 呼び出し自体は 200 を返すが、対象が別の理由で起動しきらない。すると仕組みはこう振る舞う。落ちていると判断し、作り直し、成功を記録し、しかし状態は回復していないので、次の巡回でまた落ちていると判断し、また作り直し、また成功を記録する。

この無限ループの一周ごとに「成功」のレコードが積み上がる。 気づいたときには、成功を表す記録が大量に溜まっていた。失敗は一件も無い。だから、どの監視にも引っかからなかった。

真因はこうだ。仕組みが見ていたのは「作り直しの処理が成功したか」であって、「直したかった状態が回復したか」ではなかった。成功の件数は、健全性の signal ではない。 むしろ、成功の件数が異常に増え続けていること自体が、何かが回復していないことの signal だった。

教訓

「試みが成功したか」ではなく「直したかった状態そのもの」を測る。 復旧ループを組むなら、ループが解消しようとしている条件を、ループの成否とは独立に観測する。同じ復旧が短時間に何度も走っていたら、それは成功ではなく、収束していないという警報である。


パターン 2:止まっても「成功」に見える送り出し

バックグラウンドで何かを送り続ける処理がある。ログの転送、バックアップの取得、メトリクスの送出。こうした「継続的に動き続けるもの」には、別の形のサイレント障害が潜む。

それは、止まってもエラーを出さない。ただ静かになるだけである。

送り出しが止まったとき、エラーのログは出ない。最後の送信が成功したあと、次が来ないだけだ。監視が「失敗したら鳴る」ようにできていると、この沈黙は検知できない。失敗の不在と、正常稼働は、見た目が同じになる。 ログが届かなくなっても、バックアップが取れなくなっても、画面上は何事もなく「最後の成功」が表示され続ける。そして、それが必要になったとき——障害調査でログを遡ろうとしたとき、データを復元しようとしたとき——初めて、何週間も前から止まっていたことに気づく。

教訓

継続的な処理は、失敗ではなく「陳腐化」で監視する。 「最後に成功した時刻」を持ち、それが一定時間を超えて更新されなければ鳴らす。監視すべきは「失敗が起きたか」ではなく「成功が途切れていないか」である。この 2 つは似ているようで正反対で、前者だけを監視していると、静かに止まったものを永久に見逃す。


パターン 3:台帳は「消した」と言うが、実体は残っている

クラウド上にリソースを作ったり消したりする基盤を運用していると、2 つの「状態」を持つことになる。ひとつは、自分たちの台帳——「何があるべきか」を記録したデータベース。もうひとつは、クラウド事業者の側にある実体——「実際に何があるか」。

この 2 つは、ずれる。

環境を撤収する処理が途中まで成功し、途中で失敗したとする。台帳には「削除済み」と書き込まれたが、クラウド側の実体は消えずに残った。台帳は自分に「消した」と記録しているので、もう誰もそのリソースを見に行かない。だが実体は動き続け、課金も発生し続ける。 失敗のログは残っていないか、残っていても撤収の完了レコードに上書きされて見えない。

これは前回の記事で書いた話と同じ構造だ。クラウドの一覧 API は、こちらが聞きたい質問(このプロジェクトは空か)とは違う質問に答えている。台帳もまた、こちらが知りたいこと(実体はもう無いか)ではなく、こちらが記録したこと(消したと書いた)を答えているにすぎない。

教訓

「あるべき状態」の台帳と、「実際の状態」の実体がある場合、台帳の自己申告を証拠にしない。 定期的に実体の側を読み、台帳と突き合わせる照合(reconciliation)を回す。台帳が「消した」と言っていても、事業者に問い合わせて本当に 404 が返るまでは、消えたことにしない。自分の記録は、現実の観測の代わりにはならない。


パターン 4:宣言した側と、読む側の契約がずれる

複数のコンポーネントが、構成を受け渡して動くシステムでは、もうひとつの形がある。片方が宣言した項目を、もう片方が読んでいない。 しかも、そのずれは何のエラーも出さない。

たとえば、構成を宣言する側が「この 4 つの防御を有効にする」と書く。それを実行する側が、実は 4 つのうち 0 個しか読んでいない。宣言ファイルは文法的に正しいので、検証は通る。実行する側もエラーなく動く。だが、宣言したはずの防御は一つも効いていない。双方が独立に正しく動いているので、接続部にだけ空いた穴は、どちらのテストにも映らない。

別の場面でも、まったく同じ形のバグを踏んだことがある。構成ファイルはある値を A というフィールドに書き、それを読む実装は B という別のフィールドを見ていた。両者とも単独では正しく、エラーも出ず、しかし渡したつもりの値は一度も渡っていなかった。これも、宣言と読み取りの契約がずれていた例である。

教訓

2 つのコンポーネントが構成を受け渡すなら、「読む側が、書く側の宣言を本当に全部消費しているか」をテストで固定する。 各コンポーネントが単独でコンパイルを通ることは、接続部が正しいことを意味しない。宣言された項目の一つひとつが、実際に読まれ、実際に効いていることを、端から端まで通して確かめる仕組みが要る。


共通する形と、共通する防ぎ方

4 つのパターンは、すべて同じ一点から来ている。

処理が返す「成功」は、「やってみた」ことを報告しているだけで、「効いた」ことを報告していない。 復旧の試みは成功するが、復旧は効いていない。送信の仕組みは正常だが、送信は途絶えている。削除は記録されたが、実体は消えていない。宣言は検証を通るが、読まれていない。どれも、試みの成功を、結果の成功と取り違えている。

だとすれば、防ぎ方も共通する。signal そのものを信じず、signal とは独立した ground truth(現実の、動かぬ事実)で効果を確かめる。

  • 復旧ループは、成功の件数ではなく、直したかった状態が回復したかを見る
  • 継続的な処理は、失敗ではなく、最後の成功からの経過時間を見る
  • 台帳は、自分の記録ではなく、事業者の実体を読んで突き合わせる
  • 宣言は、各側が通ることではなく、読む側が全項目を消費しているかを通しで確かめる

いずれも「調べたい対象そのもの」を観測しにいっている。調べたい対象が返してくる「成功」という自己申告を、証拠として採用しない。

4つのサイレント障害パターンと、各々で信じてはいけない成功・確かめるべきground truth・検知の仕方の対応表
図2:4 つのパターンは、すべて「signal ではなく ground truth を見る」に収束する

まとめ

前回の記事の「認証が通った、は、意図した身分で認証が通った、を意味しない」も、本稿の 4 つのパターンも、一文に畳める。

成功という signal は、試みたことを報告しているだけで、効いたことは報告していない。

エラーを出すバグは、いつか必ず気づく。だが成功を返すバグは、気づくきっかけを自分から消してしまう。だから、継続的に動くもの・自動で直るもの・外部の実体を持つもの・コンポーネント間で何かを受け渡すものを作るときは、最初から「これはどうやって静かに壊れ得るか」「静かに壊れたとき、何を見れば気づけるか」を設計に織り込んでおく必要がある。

成功を信じない。効果を、動かぬ事実で確かめる。地味だが、サイレント障害に対してはこれが唯一の構えである。

次回は、クラウド上の運用で踏んだ、もう少し具体的な落とし穴を扱う予定である。


参考リンク

記事をシェアする

さくらのクラウドの設計・構築・運用、実務ベースで相談できます

設計や移行で迷っている構成があれば、要件が固まりきっていない段階から相談として受けています。状況を共有いただければ、優先度付けから一緒に進められます。

クラウド相談をする

要件が固まりきっていない段階でも、状況を共有いただければ優先度付けから一緒に進められます。

EC

EastCloud株式会社 — さくらのクラウドを中心に、官公庁・自治体のクラウド導入と運用を支援しています