アーキテクチャ●●●○○

グレースフルデグラデーション

Graceful Degradation ・ グレースフルデグラデーション

全部が無理なら一部だけでも動かし続ける設計。完全停止ではなく品質を落として生き残る。

✦ 30秒で試す — 航海レビュー欄が消えても、客は商品さえ買えればいいこのページが表示できる時間の割合は?予想してみる

概要

グレースフルデグラデーション(graceful degradation、優雅な劣化)は、システムの一部が壊れたときに全体を止めるのではなく、品質や機能を段階的に落としながら動き続けるための設計です。「動くか、止まるか」の二択ではなく、その間に「劣化しつつ動く」という段階を意図的に用意しておく、と言い換えられます。日本語の「縮退運転」もほぼ同じ概念です。

身近な例はECサイトのレコメンド機能です。「あなたへのおすすめ」を計算するサービスが落ちたとき、商品ページごと500エラーにするのは最悪の選択です。おすすめ欄だけを人気商品ランキングに差し替える、それも無理なら欄ごと非表示にする — こうすれば、サイトの本業である「商品を見て買う」体験は無傷で生き残ります。多数の部品に依存するマイクロサービス構成では、部品のどれかが不調であることはむしろ平常であり、劣化の段階をあらかじめ設計しておくことがシステム全体の可用性を決めます。

なぜ生まれたか

素朴に作られたシステムは、依存関係が「AND条件」になりがちです。ページを組み立てるのに5つのサービスを呼び、そのうち1つでも失敗したら例外がそのまま伝播してページ全体がエラーになる。この作りでは、システム全体の可用性は全部品の可用性の掛け算になり、部品を増やすほど確実に悪化します。可用性99.9%の部品を10個直列に並べれば、全体は99%まで落ちる計算です(0.999¹⁰ ≒ 0.990。年間にすると停止時間が約9時間から約88時間へ10倍に増えます)。分散システムの規模が大きくなるにつれ、「すべてが同時に健全である」ことを前提にした設計は成立しなくなりました。

そこで発想を逆転させ、「部品の失敗は必ず起きる。起きたときに何を諦め、何を守るかを先に決めておく」というアプローチが定着しました。障害を珍しい例外ではなく通常の入力として扱い、失敗時の代替動作(フォールバック)をコードとして書いておく。これにより、致命的でない部品の障害は「気づく人も少ない小さな劣化」に格下げされます。なお、Web制作の文脈にも同名の用語があり、そちらは「最新ブラウザ向けに作り、古い環境では機能を削って表示する」方針を指します。低い環境を基準に積み上げる progressive enhancement(漸進的強化)の対義語で、「段階を設計する」という思想は共通ですが、本記事で扱うのは障害時の劣化設計のほうです。

詳細

フォールバックの階段を設計する

グレースフルデグラデーションの中心作業は、機能ごとに「劣化の階段」を設計することです。第一候補が失敗したら第二候補、それも失敗したら最終手段、と品質の降順に代替を並べます。レコメンドの例なら、パーソナライズ推薦 → 全体の人気ランキング → 静的なデフォルト表示、という三段です。下の段ほど品質は落ちますが、「何も表示できずエラーになる」よりは常に良い、という順序が保たれています。

パーソナライズ推薦品質 100% / 推薦サービス依存人気商品ランキング品質 70% / キャッシュから配信静的なデフォルト表示品質 40% / 依存なしで必ず出せる失敗・タイムアウト失敗・タイムアウト下の段ほど品質は落ちるが「エラー画面」には決してしない
フォールバックの階段 — 失敗するたびに一段下の品質へ降り、完全停止を避ける

階段を降りる引き金になるのは、依存先呼び出しの失敗やタイムアウトです。ここで重要なのは「速く諦める」ことです。フォールバックが用意されていても、第一候補を30秒待ってから切り替えたのではユーザー体験は壊れています。短いタイムアウトで見切りをつけ、サーキットブレーカーが開いている間は最初から第一候補を呼ばずに階段の下から始める。回復性パターンの仲間であるリトライ(指数バックオフ)やバルクヘッドが「失敗の検知と封じ込め」を担い、グレースフルデグラデーションが「失敗した後にどう振る舞うか」を担う、という分業です。

階段は欄(機能)ごとに独立して持つのが要点です。下の部品で、同じ故障を AND 設計とフォールバック設計に与えて比べてください。サービスを1つずつ押して止めると、AND 設計ではページごと落ち、フォールバック設計では該当の欄だけが一段ずつ降りていきます。キャッシュまで止めたとき、どの欄がもう一段降り、どの欄が「これ以上降りられない」かにも注目してください。

⚡ 体験: 1つ止まったら、ページはどこまで残るか
設計
shop.example/item/42商品情報北欧風マグカップ 350ml説明・画像・仕様価格・在庫¥1,980 在庫ありレビュー★4.2(128件)おすすめあなたへのおすすめ閲覧履歴から計算した6品商品カタログ価格・在庫レビューレコメンドキャッシュ使っていない直近のページ表示 — 青緑=完全、金=一部を劣化させて表示、朱=エラー
完全0回劣化して表示0回エラー0回平常時の可用性 99.9%⁴99.60%

商品ページは4つのサービスとキャッシュから組み立てています。いまは AND 設計(どれか1つの失敗がそのまま伝わる)です。右のレコメンドを押して止めてみてください。

最後に残った「商品情報が出せないとエラー」は、設計の失敗ではなく判断の結果です。ページの存在理由そのものである中核の機能には、降りる先を作れません。だからこそ中核にはキャッシュやレプリケーションで二重の出どころを用意し、それ以外の機能は「止まってもよい」と割り切る。この線引きがグレースフルデグラデーションの設計そのものです。

劣化の道具箱 — stale応答・機能の切り離し・軽量モード

フォールバックの実装でもっとも頼れる道具はキャッシュです。データソースが落ちていても、少し前に取得した値がキャッシュに残っていれば、「古い(stale)が妥当な応答」を返せます。為替レートや在庫数のように鮮度が命のデータでは慎重さが要りますが、商品説明やランキングのようなデータなら「10分前の値」で困る場面はほとんどありません。平常時は鮮度のために短くしているキャッシュ寿命を、障害時だけ「期限切れでも使ってよい」と緩める戦略は劣化設計の定番で、HTTP ではこれを Cache-Control の stale-if-error 指示で表します(RFC 5861)。よく並べて語られる stale-while-revalidate は別の指示で、こちらは障害とは関係なく「期限切れの値をいったん返し、裏で取り直す」ことで応答を速くするためのものです。

もう一つの道具は、機能単位の切り離しです。フィーチャーフラグをキルスイッチとして仕込んでおけば、障害や過負荷の際に「レコメンド」「画像の高解像度配信」「リアルタイム通知」といった非中核機能を運用判断で即座に落とせます。デプロイなしで負荷の源を止められるため、インシデント対応の初動で効く道具です。さらに進んで、高負荷時にシステム自身が重い処理を自動で間引く設計もあります。過負荷時に一部リクエストを意図的に拒否するロードシェディングや、上流に減速を伝えるバックプレッシャーは、「全員に遅い応答」より「一部を断って残りに正常な応答」を選ぶという意味で、劣化設計の一形態といえます。

落とし穴 — 静かな劣化と、劣化パスの品質

グレースフルデグラデーションには特有の危険があります。それは劣化が静かに起きることです。エラー画面なら誰でも気づきますが、「おすすめ欄が人気ランキングにすり替わっている」状態は、ユーザーからの通報もなく何週間も見過ごされ得ます。フォールバックが発動したら必ずメトリクスとログに残し、発動率の上昇でアラートを出す — 劣化設計は監視とセットで初めて完成します。「フォールバックのおかげで障害に気づかなかった」は成功談ではなく、根本原因の放置です。

もう一つの落とし穴は、フォールバック自体の品質です。劣化パスは平常時に通らないコードなので、いざ発動したら壊れていた、フォールバック先が本命より重くて共倒れした、という事故が起こりがちです。劣化パスもテストに含め、カオスエンジニアリングの手法で依存先の障害を注入して定期的に「階段を実際に降りてみる」ことが、絵に描いた縮退にしないための実務です。何をどこまで守るかの基準は、サービスのSLOから逆算して決めます。「決済は絶対、閲覧は劣化許容、レコメンドは停止許容」のように機能へ優先度を付けておくことが、障害の夜に迷わないための設計図になります。

試問

商品ページは、4つのサービス(商品カタログ・価格と在庫・レビュー・レコメンド)とキャッシュから組み立てられています。右のサービスを押すと止まり(もう一度押すと戻る)、設計は「AND 設計(どれか1つの失敗でページごとエラー)」と「フォールバック設計(欄ごとに代わりの手段を持つ)」を切り替えられます。

✦ 命題挑戦中

5つのサービスのうち4つを止めても、商品ページを表示し続けよ

  • 5つのサービスのうち 4つが止まっている
  • それでも商品ページが表示されている(エラーでない)
⚡ 体験: 4つ止めても、ページを出し続ける
設計
shop.example/item/42商品情報北欧風マグカップ 350ml説明・画像・仕様価格・在庫¥1,980 在庫ありレビュー★4.2(128件)おすすめあなたへのおすすめ閲覧履歴から計算した6品商品カタログ価格・在庫レビューレコメンドキャッシュ使っていない直近のページ表示 — 青緑=完全、金=一部を劣化させて表示、朱=エラー
完全0回劣化して表示0回エラー0回平常時の可用性 99.9%⁴99.60%

商品ページは4つのサービスとキャッシュから組み立てています。いまは AND 設計(どれか1つの失敗がそのまま伝わる)です。右のレコメンドを押して止めてみてください。