※小説ではない※専門書 要約資料集 為替(換算)3.9万円でもらう 紐解集生成 専門 初入門 資料 作:{作者名}
※物語はフィクションです ※
※即時通報案件は専門家にご通報ください※
※お手数ですが疑問点は各分野でご確認いただけましたら幸いです※
# BOOK-0366 情報防衛と復旧シリーズ 第7巻: 可用性・信頼性工学(SRE) — 止まらないためではなく、止まっても致命傷にしないための設計
> 情報防衛と復旧シリーズ(全12巻・BOOK-0360〜0371・設計書=CATALOG_情報防衛と復旧シリーズ.md)第7巻。ガイド役: Fable 5 監修 / Sonnet 5 執筆(脚本班)
> トーン規約: GAKUMON_UNIVERSE.md準拠。専門用語は初出で必ず説明する。
> **値札**: 「一日停止・全システム再構成の段階判断」という特命業務のうち、本巻が担うのは**構成し直し**の段階——判定(前々巻)と復旧(前巻)の技術で戻ってきたシステムを、次に同じ原因で丸一日止まらないよう、冗長化・フェイルオーバー・段階的縮退という設計であらかじめ組み直しておく仕事——である。
> **安全枠(§16.18・本巻での適用範囲・最重要)**: 本巻は防御・設計・教育に限定する。実在システムへの侵入手順・動作するエクスプロイト・攻撃の再現コード・可用性を意図的に奪う攻撃の実行手順は一切書かない。そうした攻撃という脅威の**存在**には防御的な観点から言及するが、その実行方法は記載しない。可用性の設計は「何を用意すれば、何が守られるか・何が守られないか」という防御的視点でのみ扱う(IMPORTANT: authorized security testing/defensive securityの枠内)。**誇張禁止(§16.5)**: 「この構成にすれば絶対に落ちない」等は書かない。冗長化・段階的縮退は障害の影響範囲と復旧までの時間を減らすが、可用性をゼロにはできない——公表値にもとづき、幅を持たせて語る、という正直な水準で書く。
> 接続先: →BOOK-0360『情報セキュリティ総論』(全巻の土台。同書第二章が扱うCIA三要素のうち可用性〈Availability〉を、本巻は専門に扱う)、→BOOK-0364『フォレンジクスとログ解析』(前々巻。本巻の入口の物語は同書が判定した深夜3時の在庫管理システム事件の続きである)、→BOOK-0365『バックアップと災害復旧』(前巻。同書は「戻ってこられるか」を扱い、本巻は「そもそも止まりにくくする・止まっても致命傷にしない」を扱う——両者は表裏の関係にある)、→BOOK-0367『監視と観測可能性』(次巻。本巻第九章のSLI/SLOは、そちらが扱う計測基盤があって初めて実測できる)、→BOOK-0070/0119『情報派生 ネットワーク』第1・2巻(本巻第三章・第十一章で扱う冗長経路・CAP定理・負荷分散は、そちらの通信理論の上に立つ)、→BOOK-0358t『PC創造大全 目録X OS導入と保守の技』(保守という日常業務との接続)、→BOOK-0359b/d『Editor創造大全』第2部・第4部(本巻第五章・第十一章で引用する冪等性・保存則検査は、そちらの実装が先行事例)。
> 水準: 一〜十二(単一障害点とは何かという土台から、可用性を測る物差し、冗長化の基本形、フェイルオーバー、リトライと冪等性、タイムアウトとサーキットブレーカー、段階的縮退、過負荷をさばく設計、SLI/SLO/エラーバジェット、カオスエンジニアリングとポストモーテム、分散系の可用性設計、そして講師級として「なぜSREという職能が生まれたか」という理論上のメタ的推移までを扱う。初心者→熟練者→上級専門家→講師級の四段は、第一〜三章/第四〜七章/第八〜十章/第十一〜十二章に対応する)。
---
# BOOK-0366 情報防衛と復旧シリーズ 第7巻: 可用性・信頼性工学(SRE) — 止まらないためではなく、止まっても致命傷にしないための設計
> 情報防衛と復旧シリーズ(全12巻・BOOK-0360〜0371・設計書=CATALOG_情報防衛と復旧シリーズ.md)第7巻。ガイド役: Fable 5 監修 / Sonnet 5 執筆(脚本班)
> トーン規約: GAKUMON_UNIVERSE.md準拠。専門用語は初出で必ず説明する。
> **値札**: 「一日停止・全システム再構成の段階判断」という特命業務のうち、本巻が担うのは**構成し直し**の段階——判定(前々巻)と復旧(前巻)の技術で戻ってきたシステムを、次に同じ原因で丸一日止まらないよう、冗長化・フェイルオーバー・段階的縮退という設計であらかじめ組み直しておく仕事——である。
> **安全枠(§16.18・本巻での適用範囲・最重要)**: 本巻は防御・設計・教育に限定する。実在システムへの侵入手順・動作するエクスプロイト・攻撃の再現コード・可用性を意図的に奪う攻撃の実行手順は一切書かない。そうした攻撃という脅威の**存在**には防御的な観点から言及するが、その実行方法は記載しない。可用性の設計は「何を用意すれば、何が守られるか・何が守られないか」という防御的視点でのみ扱う(IMPORTANT: authorized security testing/defensive securityの枠内)。**誇張禁止(§16.5)**: 「この構成にすれば絶対に落ちない」等は書かない。冗長化・段階的縮退は障害の影響範囲と復旧までの時間を減らすが、可用性をゼロにはできない——公表値にもとづき、幅を持たせて語る、という正直な水準で書く。
> 接続先: →BOOK-0360『情報セキュリティ総論』(全巻の土台。同書第二章が扱うCIA三要素のうち可用性〈Availability〉を、本巻は専門に扱う)、→BOOK-0364『フォレンジクスとログ解析』(前々巻。本巻の入口の物語は同書が判定した深夜3時の在庫管理システム事件の続きである)、→BOOK-0365『バックアップと災害復旧』(前巻。同書は「戻ってこられるか」を扱い、本巻は「そもそも止まりにくくする・止まっても致命傷にしない」を扱う——両者は表裏の関係にある)、→BOOK-0367『監視と観測可能性』(次巻。本巻第九章のSLI/SLOは、そちらが扱う計測基盤があって初めて実測できる)、→BOOK-0070/0119『情報派生 ネットワーク』第1・2巻(本巻第三章・第十一章で扱う冗長経路・CAP定理・負荷分散は、そちらの通信理論の上に立つ)、→BOOK-0358t『PC創造大全 目録X OS導入と保守の技』(保守という日常業務との接続)、→BOOK-0359b/d『Editor創造大全』第2部・第4部(本巻第五章・第十一章で引用する冪等性・保存則検査は、そちらの実装が先行事例)。
> 水準: 一〜十二(単一障害点とは何かという土台から、可用性を測る物差し、冗長化の基本形、フェイルオーバー、リトライと冪等性、タイムアウトとサーキットブレーカー、段階的縮退、過負荷をさばく設計、SLI/SLO/エラーバジェット、カオスエンジニアリングとポストモーテム、分散系の可用性設計、そして講師級として「なぜSREという職能が生まれたか」という理論上のメタ的推移までを扱う。初心者→熟練者→上級専門家→講師級の四段は、第一〜三章/第四〜七章/第八〜十章/第十一〜十二章に対応する)。
---
## 入口の物語 — 深夜3時の事件、その続き。「なぜ、たった一台が全部を止めたのか」
深夜3時、在庫管理システムが止まった夜のことを、三度目に思い出してほしい。前々巻(BOOK-0364)は、証拠と検算から「何が、いつ、どう壊れたか」を突き止めた——`batch-svc`という定型処理アカウントが在庫調整のAPIを呼び出した直後、データベース接続プールが枯渇し、アプリケーションが自動的に再試行し、同じ書き込みが2回実行された可能性が高い、という判定だった。前巻(BOOK-0365)は、この判定を受け取り、改竄前の状態まで確実に戻すバックアップと復元の技術を積み上げた。データは、もう元に戻っている。
しかし、経営陣の指示は「原因を突き止めて直せ」だけではなかった。「今日一日、全システムを止めてでも」という一文には、もう一つの重い意味が隠れている——なぜ、たった一つのデータベース接続プールが枯渇しただけで、システム全体が丸一日止まるほどの騒ぎになったのか、という問いである。
答えは、在庫管理システムの構成図を見れば、拍子抜けするほど単純だった。データベースは1台しか動いていなかった。接続プールを持つアプリケーションサーバーも1台しか動いていなかった。予備の機体はなく、切り替え先の経路もなく、負荷を逃がす先もなかった。1台のプロセスが根を上げれば、システム全体が根を上げる——この構成そのものが、今回の一日停止の、本当の根本原因だったのである。
本巻が扱うのは、この「たった1台が全部を道連れにする」という構造そのものに手を入れる仕事である。専門的にはこれを**可用性・信頼性工学(SRE、Site Reliability Engineering)**と呼ぶ。前々巻が「判定」を、前巻が「戻ってこられるかどうか」を扱ったのに対し、本巻は「そもそも止まりにくくする」「止まっても、致命傷にしない」という、一段先回りした設計の仕事を扱う。
単一の弱点を見つける目(第一章)。止まりにくさを数字で語る物差し(第二章)。予備を用意する冗長化の基本形(第三章)。予備へ自動で切り替えるフェイルオーバー(第四章)。再試行しても壊れない設計(第五章)。連鎖して共倒れしないためのタイムアウトとサーキットブレーカー(第六章)。全滅ではなく一部の機能だけを残して耐える段階的縮退(第七章)。押し寄せる負荷をさばく仕組み(第八章)。信頼性を数値の契約にするSLI・SLO(第九章)。わざと壊して学ぶカオスエンジニアリングと、非難のない事後検証(第十章)。複数台に散らばったデータの整合性まで含めた分散系の設計(第十一章)。そして最後に、なぜ「SRE」という専門職がこの世に生まれる必要があったのか、という理論上のメタ的推移(第十二章)。
深夜3時の在庫管理システムが、二度と同じ理由で丸一日止まらないようにする——この一冊の値札は、そこにある。
---
## 第一章: 単一障害点(SPOF)とは何か(水準一)
### たった1つが壊れると全部が壊れる、という構造
**単一障害点(たんいつしょうがいてん、SPOF、Single Point of Failure、水準一: システムを構成する要素のうち、それが1つ故障するだけでシステム全体が停止してしまう箇所)**というのは、可用性・信頼性工学がまっさきに探しに行く「弱点」の名前である。単一障害点は、ハードウェア(1台しかないサーバー、1本しかない電源ケーブル)であることもあれば、ソフトウェア(1つしかないプロセス、1つしかないデータベース接続)であることもあり、さらには人間(手順を知っているのが1人しかいない)であることさえある。
入口の物語で見た在庫管理システムの構成は、教科書的な単一障害点の実例である。データベースが1台しかない以上、そのデータベースが応答不能になれば、システム全体が応答不能になる。これは「バグ」ではない。設計の時点で意図的にせよ、なりゆきにせよ、「予備を用意しない」という選択がされていた、という構成上の事実である。
単一障害点という考え方の裏には、もう一つの重要な洞察がある——**可用性は、鎖の中で一番弱い輪の強さで決まる**という考え方である。どれほど頑丈な部品を99個そろえても、100個目が単一障害点であれば、システム全体の信頼性はその1個の弱さに支配される。この直感は、次章(第二章)で数式として検算する。
### 単一障害点の見つけ方 — 構成図に「1」を探す
単一障害点を見つける作業自体は、実は難しい理論を必要としない。システムの構成図(サーバー・ネットワーク経路・電源・人員まで含めた依存関係の図)を描き、それぞれの要素について「これが1つ壊れたとき、システム全体は動き続けるか」を、要素ひとつひとつに問うていくだけでよい。答えが「動き続けない」であれば、その要素は単一障害点である。
### 検算1 — 在庫管理システムの構成図から、単一障害点を洗い出す
入口の物語の在庫管理システムを、簡略化した構成図で表すと、次のようになる。
```
[ロードバランサ 1台] → [アプリケーションサーバー 1台] → [データベース 1台]
↑
[接続プール 1つ]
```
この図の各要素に「これが1つ壊れたら、システム全体は動き続けるか」を問うと、次の結果が得られる。
```
ロードバランサ(1台) → 壊れたら全体停止 → 単一障害点
アプリケーションサーバー(1台) → 壊れたら全体停止 → 単一障害点
データベース(1台) → 壊れたら全体停止 → 単一障害点
接続プール(1つ・上限あり) → 枯渇したら全体停止 → 単一障害点
```
驚くべきことに、この構成図には**4つ**の単一障害点が存在する。実際に深夜3時の事件で表面化したのは接続プールの枯渇だったが、もしロードバランサやアプリケーションサーバーが先に壊れていたとしても、同じように全体停止が起きていたはずである。単一障害点は、事件が起きるまで気づかれないことが多い——なぜなら、壊れるまでは「1台で十分動いている」ように見えるからである。
### コラム — 「動いているから大丈夫」という罠
単一障害点の恐ろしさは、平常時にはまったく姿を見せないことにある。1台構成のデータベースは、平常時には2台構成のデータベースと見分けがつかないほど普通に動く。違いが表面化するのは、その1台が実際に壊れた瞬間だけである。この「壊れるまで気づかれない」という性質が、単一障害点の除去を後回しにされがちな理由でもある——予算や工数を投じて予備を用意しても、平常時には目に見える効果がなく、「壊れなかった」という結果でしか投資が報われないためである。この構造は、前巻(BOOK-0365)が指摘する「バックアップも、使われるまでは正しく機能しているかどうか分からない」という論点と、同じ根を持っている。
### 単一障害点は、必ずしも技術要素だけとは限らない
単一障害点は、サーバーや配線といった物理的な要素に限らない。**「この手順を知っているのは、あの1人だけだ」**という状態も、立派な単一障害点である。担当者が休暇中、あるいは退職した直後に障害が起きると、技術的には冗長化されていたはずのシステムが、実際には「対応できる人間がいない」という理由で、丸一日止まったままになることがある。本シリーズ第九巻『監査・統制とコンプライアンス』が扱う職務分掌(→BOOK-0364第九章でも触れた考え方)は、こうした「人」の単一障害点を減らすための制度側の答えでもある。
### よくある誤解 — 「バックアップがあるから単一障害点ではない」
「データベースは1台だが、毎晩バックアップを取っているから単一障害点ではない」という考え方は、半分正しく、半分誤っている。バックアップは、データが失われたときに**戻ってくる**ための備えであり、前巻(BOOK-0365)が扱った災害復旧の仕事である。しかし、バックアップからの復元には、多くの場合、数十分から数時間という**時間**がかかる。その間、システムは止まったままである。単一障害点を「無くす」ことと、単一障害点が壊れたときに「戻ってこられるようにしておく」ことは、似ているようでまったく別の設計判断であり、本巻(可用性)と前巻(災害復旧)が、それぞれ別の巻として独立している理由でもある。
---
> **定着量の目安(第一章)**: 自分の身近なシステム(学校や職場のネットワーク、よく使うアプリ)を1つ選び、検算1の型で構成図を描き、単一障害点を3つ以上洗い出す練習をすると定着する。あわせて「動いているから大丈夫」という罠を、自分の言葉で説明できることを目安とする。
---
## 第二章: 可用性を測る物差し — 稼働率・MTBF・MTTR(水準二)
### 「だいたい落ちない」を、数字で語る
前章で見た単一障害点という考え方は、「弱点がある/ない」という定性的(はい/いいえ)な話だった。しかし実務では、「このシステムはどれくらい信頼できるのか」を、数字で語れなければならない場面が多い。ここで使われる基本的な物差しが**可用性(かようせい、availability、水準二: システムが、あらかじめ約束された機能を提供できている時間の割合)**である。
可用性は、多くの場合パーセンテージで表され、「99.9%」のように語られる。この一見地味な数字の違いが、実際にはどれほどの時間の差になるのかを、次の検算で確かめよう。
### 検算2 — 「ナインの数」が意味する年間停止時間
1年間の時間はおよそ8,766時間(365.25日×24時間、うるう年を考慮した近似値)である。可用性のパーセンテージから、それぞれ年間の停止許容時間がどれくらいになるかを計算してみよう。
```
可用性 停止時間の目安(年間) 通称
99% 8,766時間×(1−0.99)=87.66時間 ≈ 3.65日 「2ナイン」
99.9% 8,766時間×(1−0.999)=8.766時間 ≈ 8.8時間 「3ナイン」
99.99% 8,766時間×(1−0.9999)=0.8766時間 ≈ 52.6分 「4ナイン」
99.999% 8,766時間×(1−0.99999)=0.08766時間 ≈ 5.3分 「5ナイン」
```
「99%」と「99.9%」の違いは、数字の上ではわずか0.9ポイントに見えるが、年間停止時間で見ると3.65日と8.8時間という、桁違いの差になる。この計算は近似値であり、実際の運用では停止時間の数え方(計画停止を含むか否か等)によって定義が変わる場合があるため、契約や社内基準を確認する際には、必ずその定義も併せて確認する必要がある。
### MTBFとMTTR — 「壊れにくさ」と「直しやすさ」を分けて測る
可用性という1つの数字の裏には、実は2つの異なる性質が隠れている。**MTBF(えむてぃーびーえふ、Mean Time Between Failures、平均故障間隔、水準二: 故障が発生してから、次の故障が発生するまでの平均時間)**は「どれくらい壊れにくいか」を表し、**MTTR(えむてぃーてぃーあーる、Mean Time To Repair/Recovery、平均修復時間、水準二: 故障が発生してから、正常な状態に復旧するまでの平均時間)**は「どれくらい早く直せるか」を表す。この2つを使うと、可用性は次の式で近似できる。
```
可用性 ≈ MTBF ÷ (MTBF + MTTR)
```
この式が語っているのは、可用性を上げる方法が実は2種類ある、という重要な事実である。1つは、故障そのものを減らしてMTBFを大きくすること(壊れにくくする)。もう1つは、故障からの復旧を速めてMTTRを小さくすること(直しやすくする)。多くの現場では前者(壊れにくくする)にばかり注目しがちだが、実務上はMTTRを縮める投資のほうが、費用対効果が高い場合も多い——これは第四章(フェイルオーバー)で扱う自動切替の価値の根拠になる。
### 検算3 — MTBFとMTTRから、可用性を逆算する
入口の物語の在庫管理システムが、平均して30日(720時間)に1回、何らかの障害を起こしていたと仮定しよう(MTBF=720時間)。手作業での障害対応(担当者への連絡、原因調査、手動での再起動)には平均して30分(0.5時間)かかっていたとする(MTTR=0.5時間)。
```
可用性 ≈ 720 ÷ (720 + 0.5) = 720 ÷ 720.5 ≈ 0.999306 ≈ 99.93%
```
この可用性から年間停止時間を逆算すると、8,766時間×(1−0.999306)≈6.1時間となる。この検算は、第四章で「自動フェイルオーバーによってMTTRを30分から数十秒へ縮めると、可用性はどれだけ改善するか」を再検算する際の、比較の基準値として使う。
### コラム — 可用性は掛け算で減っていく
複数のコンポーネントが直列(どれか1つでも壊れたら全体が止まる関係)につながっているとき、システム全体の可用性は、個々のコンポーネントの可用性を**掛け合わせた**値になる。たとえば99.9%の可用性を持つWebサーバーと、99.5%の可用性を持つデータベースサーバーが直列につながっている場合、システム全体の可用性は0.999×0.995=0.994005、つまり約99.40%まで下がる。個々の部品がどれだけ信頼できても、直列に並べれば並べるほど、全体の可用性はその積として下がっていく——これが、単一障害点を減らすだけでなく、そもそも直列の依存関係そのものを減らす設計(次章で扱う冗長化)が重要とされる、数学的な理由である。
### よくある誤解 — 「可用性99.9%だから、1000回に1回失敗する」ではない
可用性のパーセンテージは、**時間**に対する割合であり、**回数**に対する割合ではない。「可用性99.9%」は「1000回のリクエストのうち999回成功する」という意味ではなく、「1年間のうち99.9%の時間帯において、システムが正常に機能している」という意味である。両者は似ているようで異なる指標であり、リクエストの成功率(エラー率)を測る指標は、次章以降で扱うSLI(サービスレベル指標、第九章)という、また別の物差しで語られることが多い。
---
> **定着量の目安(第二章)**: 検算2の表(99%・99.9%・99.99%・99.999%)を、自分で電卓を使って計算し直し、値が一致することを確認する練習をすると定着する。あわせて、検算3の型(MTBF・MTTRから可用性を逆算する)を、MTBFとMTTRの数値を変えて3パターンほど自分で計算してみることを目安とする。
---
## 第三章: 冗長化の基本形 — 直列と並列、N+1という考え方(水準三)
### 予備を用意する、という発想
**冗長化(じょうちょうか、redundancy、水準三: システムを構成する要素に、あらかじめ予備を用意しておき、1つが故障しても全体としては機能し続けられるようにする設計)**は、単一障害点(第一章)に対する、もっとも基本的な処方箋である。冗長化という言葉は、日常語では「無駄が多い」というやや否定的な響きを持つが、可用性・信頼性工学の文脈では、まったく逆の、積極的な設計判断を指す。
冗長化の基本形は、コンポーネントを**並列**に配置することである。第二章のコラムで見たとおり、直列につながったコンポーネントの可用性は掛け算で下がっていくが、並列に配置されたコンポーネント(どちらか一方が生きていれば全体が機能する関係)の可用性は、逆に足し合わされる方向で高くなる。
### 検算4 — 並列冗長化で、可用性がどれだけ改善するか
第二章のコラムで、単一のデータベースサーバー(可用性99.5%と仮定)が単一障害点になっていたことを思い出そう。この可用性99.5%のデータベースサーバーを、まったく同じ性能を持つ機体を、もう1台並列に用意して冗長化すると、どうなるだろうか。
並列構成全体が停止するのは、**両方**のサーバーが同時に壊れている場合だけである。個々のサーバーが故障している確率は(1−0.995)=0.005であり、2台が同時に故障している確率は、両者の故障が互いに無関係(独立)だと仮定すると、0.005×0.005=0.000025となる。したがって、並列構成全体の可用性は次のようになる。
```
並列構成の可用性 = 1 − (1−0.995)×(1−0.995) = 1 − 0.000025 = 0.999975 ≈ 99.9975%
```
単体では99.5%だった可用性が、まったく同じ機体をもう1台並べるだけで、99.9975%まで向上する。年間停止時間に換算すると、単体では8,766時間×0.005≈43.8時間だったものが、並列構成では8,766時間×0.000025≈0.22時間(約13分)まで縮む。この検算が示すとおり、**冗長化は、個々の部品の性能を上げなくても、台数を増やすだけでシステム全体の信頼性を大きく引き上げられる**、という強力な性質を持つ。
ただし、この計算には重要な前提がある——「2台の故障が互いに無関係(独立)である」という仮定である。もし2台が同じ電源、同じネットワークスイッチ、同じデータセンターに接続されていた場合、片方を壊す原因(停電、ネットワーク障害、地震等)がもう片方も同時に壊す可能性が高くなり、「独立している」という前提そのものが崩れる。この落とし穴は、次のコラムで扱う。
### N+1という考え方
冗長化の設計でよく使われる表現に**N+1(えぬぷらすわん、水準三: システムの稼働に必要な台数をNとしたとき、それより1台多い台数を用意しておく冗長化の設計方針)**がある。たとえば、通常の負荷をさばくのに3台のサーバーが必要(N=3)なシステムに対して、予備を1台追加して4台構成にすることをN+1と呼ぶ。予備を2台追加する場合はN+2と呼ばれ、要求される信頼性の高さに応じて、予備の台数を増やしていく。
N+1構成の利点は、通常の運用中に1台が保守やアップグレードのために停止しても(計画停止)、残りのN台で通常の負荷をさばき続けられる点にある。これにより、保守作業のために計画的にシステム全体を止める必要がなくなる。前巻(BOOK-0365)が扱う物理分離バックアップの考え方とは異なり、N+1は「止めずに保守する」ための冗長化である、という違いを押さえておくとよい。
### コラム — 「同じ場所に置かない」という、もう一つの冗長化
冗長化の効果を最大限に発揮させるには、予備の機体を**別の障害ドメイン**に置くことが欠かせない。障害ドメインとは、同じ原因で同時に故障し得る範囲のことであり、同じ電源系統、同じネットワークスイッチ、同じラック、同じデータセンター、同じ地域(地震・水害等の広域災害の影響範囲)が、それぞれ1つの障害ドメインになり得る。2台のサーバーを冗長化したつもりでも、両方が同じ電源タップに接続されていれば、そのタップが1本壊れただけで両方が同時に停止してしまう——これは、検算4で仮定した「2台の故障が独立している」という前提が崩れる典型例である。本シリーズ姉妹巻BOOK-0070第六章が扱う「網の強靭さの秘密」(ルーティングの冗長経路設計)や、BOOK-0119第七章が扱うCDN(コンテンツ配信網、地理的に分散したサーバー群)は、この「同じ場所に置かない」という発想を、ネットワークの領域で実践した実例である。
### アクティブ-アクティブとアクティブ-スタンバイ
冗長化された複数の機体を、どう運用するかにも2つの型がある。**アクティブ-アクティブ(水準三: 冗長化された複数の機体が、平常時からすべて同時に稼働し、負荷を分担する構成)**は、予備の機体を「待たせておく」のではなく、平常時から実際の処理を分担させる。一方、**アクティブ-スタンバイ(水準三: 冗長化された複数の機体のうち1台だけが平常時に稼働し、残りは待機状態で、主系が故障したときに初めて動き出す構成)**は、予備の機体を普段は休ませておき、いざというときだけ動かす。アクティブ-アクティブは平常時のリソースを無駄にしない利点があるが、切替の仕組みが複雑になりやすい。アクティブ-スタンバイは仕組みが単純な一方、予備の機体が「実際に動くかどうか」を平常時に確認しにくいという弱点を持つ——この弱点への対処は、次章(第四章)のヘルスチェックの話につながる。
### よくある誤解 — 「2台あれば冗長化は万全」ではない
「サーバーを2台に増やしたから、これでもう単一障害点はない」という考え方には、少なくとも2つの見落としがあり得る。1つは、前述の「障害ドメインを分けていなければ、2台も1台と同じように同時に落ちる」という見落としである。もう1つは、2台の**先**にある単一障害点——たとえば、2台のアプリケーションサーバーが、結局は同じ1台のデータベースに接続している場合、データベースという単一障害点はまだ残ったままである。冗長化は、システム全体を構成図として描き、すべての層(第一章の検算1で見たロードバランサ・アプリケーションサーバー・データベース・接続プール)に対して、それぞれ個別に検討する必要がある。
---
> **定着量の目安(第三章)**: 検算4の型(個々の可用性から並列構成全体の可用性を計算する)を、可用性の値を変えて5パターンほど計算する練習をすると定着する。あわせて、アクティブ-アクティブとアクティブ-スタンバイの違いを、それぞれの利点と弱点を添えて説明できることを目安とする。
---
## 第四章: フェイルオーバー — ヘルスチェックと自動切替(水準四)
### 予備がいても、切り替わらなければ意味がない
第三章で見た冗長化は、あくまで「予備を用意する」という話だった。しかし、予備の機体がただそこに存在しているだけでは、主系が故障した瞬間にシステムが止まってしまうことに変わりはない。予備へ実際に処理を切り替える仕組みがあって、初めて冗長化は意味を持つ。この切替の仕組みを**フェイルオーバー(ふぇいるおーばー、failover、水準四: 稼働中の機体に障害が発生したとき、処理を予備の機体へ自動的に引き継がせる仕組み)**と呼ぶ。
フェイルオーバーが成立するためには、2つの要素が欠かせない。1つは、「主系が壊れたこと」を検知する仕組みであり、もう1つは、検知した後に「実際に予備へ切り替える」仕組みである。
### ヘルスチェック — 「生きているか」を定期的に問う
**ヘルスチェック(へるすちぇっく、health check、水準四: システムやサービスに対して定期的に問い合わせを送り、正常に応答するかどうかを確認する仕組み)**は、フェイルオーバーの検知側を担う。単純なヘルスチェックは、たとえば「5秒ごとに、対象のサーバーへ軽い問い合わせ(pingや、ごく軽いAPI呼び出し)を送り、決まった時間内に正常な応答が返ってくるか」を確認する形で実装される。
ヘルスチェックの設計には、いくつかの調整すべき要素がある。**間隔(どれくらいの頻度で問い合わせるか)**が短すぎると、ヘルスチェック自体がシステムへの負荷になる。逆に長すぎると、故障の検知が遅れる。**しきい値(何回連続で失敗したら「故障」と判定するか)**が小さすぎると、たまたま1回だけ応答が遅れただけで、正常な機体を誤って「故障」と判定してしまう(この誤判定は**フラッピング**と呼ばれる現象の一因になる)。しきい値が大きすぎると、今度は本当の故障の検知が遅れる。
### 検算5 — 自動フェイルオーバーが、MTTRと可用性をどう変えるか
第二章の検算3で、手作業での障害対応にMTTR=0.5時間(30分)がかかっていた在庫管理システムを思い出そう。ヘルスチェックによる自動フェイルオーバーを導入し、「5秒間隔で問い合わせ、3回連続失敗(15秒)で故障と判定し、切替に10秒かかる」という設定にした場合、MTTRは次のようになる。
```
検知にかかる時間: 5秒×3回 = 15秒
切替にかかる時間: 10秒
合計MTTR: 25秒 ≈ 0.00694時間
```
このMTTRを、第二章の可用性の式(可用性 ≈ MTBF ÷ (MTBF + MTTR))に、MTBF=720時間のまま当てはめると、次のようになる。
```
可用性 ≈ 720 ÷ (720 + 0.00694) ≈ 0.9999904 ≈ 99.999%
```
手作業のMTTR=0.5時間では可用性99.93%(年間停止時間約6.1時間)だったものが、自動フェイルオーバーでMTTR=25秒まで縮めると、可用性99.999%(年間停止時間約5.3分)まで改善する。この検算は、第二章のコラムで触れた「MTBFを上げる(壊れにくくする)よりも、MTTRを下げる(直しやすくする)投資のほうが、費用対効果が高い場合がある」という主張の、具体的な裏付けになっている。
### スプリットブレインという落とし穴
フェイルオーバーの設計には、独特の難しい落とし穴がある。**スプリットブレイン(すぷりっとぶれいん、split-brain、水準四: ネットワークの分断などによって、複数の機体がそれぞれ「自分こそが主系だ」と誤認し、同時に主系として動いてしまう状態)**である。たとえば、主系と予備系が、実際にはどちらも生きているのに、両者を結ぶネットワーク経路だけが切れてしまったとする。予備系は「主系からの応答がない」と判断してフェイルオーバーを実行し、自分を新しい主系として動き出す。ところが主系自身は、実は生きたまま動き続けており、こちらも「自分が主系だ」と思い込んだままである。この結果、2つの機体が同時に書き込みを受け付けてしまい、データの不整合が生じる。
スプリットブレインへの対処としては、**クォーラム(定足数、水準四: 過半数の合意がなければ、主系としての切替を実行しない、という多数決の仕組み)**を用いる方法が広く知られている——3台以上の奇数台で構成し、過半数(2台以上)から「主系が応答しない」という合意が得られたときだけフェイルオーバーを実行することで、ネットワークの一部分断だけでは誤って複数の主系が生まれないようにする。クォーラムという考え方は、本巻第十一章で分散系のデータ整合性の文脈でも改めて登場する。
### コラム — フェイルオーバーそのものが、新しい障害の火種になることもある
フェイルオーバーの仕組み自体が正しく動くかどうかは、平常時にはほとんど検証されない、という皮肉な事実がある。主系がめったに故障しないシステムほど、フェイルオーバーの仕組みが実際に発動する機会も少なく、「いざ発動してみたら、予備系の設定が古くて動かなかった」「切替スクリプトに手を入れて以来、一度も試していなかった」という事態が起こり得る。この落とし穴への対処が、第十章で扱うカオスエンジニアリング(意図的に障害を起こして、フェイルオーバーが本当に機能するかを平常時に確認しておく実践)である。
### よくある誤解 — 「フェイルオーバーは一瞬で終わる」ではない
フェイルオーバーという言葉の響きから、「一瞬で無停止に切り替わる」という印象を持たれがちだが、実際には検算5で見たとおり、検知にかかる時間と切替にかかる時間の両方が必要であり、完全に無停止(ゼロダウンタイム)にするのは容易ではない。特に、進行中の処理(たとえば書き込み中のトランザクション)がある場合、その処理をどう扱うか(再試行するか、失敗として利用者に伝えるか)という設計判断が別途必要になる——これが、次章で扱うリトライと冪等性の話につながっていく。
---
> **定着量の目安(第四章)**: 検算5の型(検知時間+切替時間からMTTRを計算し、可用性を再計算する)を、間隔・しきい値・切替時間の数値を変えて3パターンほど計算する練習をすると定着する。あわせて、スプリットブレインがなぜ起こるのか、クォーラムがなぜそれを防げるのかを、自分の言葉で説明できることを目安とする。
---
## 第五章: リトライと冪等性 — 再送しても壊れない設計(水準五)
### 「もう一度試す」は、もっとも自然な対処である
障害が起きたとき、もっとも直感的な対処は「もう一度試してみる」ことである。この考え方を仕組みとして組み込んだものを**リトライ(りとらい、retry、水準五: 処理が失敗したとき、一定の条件のもとで、その処理を自動的にもう一度実行する仕組み)**と呼び、総関数辞書ではFUNC-0293(リトライ、retry)に一般化されている。リトライは、一時的な障害(ネットワークの瞬断、サーバーの一時的な過負荷)に対しては非常に有効な対処であり、可用性・信頼性工学の現場でもっとも広く使われる技法の1つである。
しかし、前々巻(BOOK-0364)の検算3を思い出してほしい。深夜3時の在庫管理システムのログには、次の記録があった。
```
[システムログ] 02:59:02 service=inventory-db level=ERROR msg="connection pool exhausted"
[システムログ] 02:59:03 service=inventory-app level=WARNING msg="retrying write (attempt 1/3)"
[アクセスログ] 02:59:03 user=batch-svc method=POST path=/api/inventory/adjust status=200
```
このログが示すとおり、アプリケーションは接続プール枯渇のエラーに対してリトライ(FUNC-0293)を実行し、2回目の書き込みはstatus=200(成功)として記録されている。ここに、リトライという技法の**危険な裏面**が現れている——1回目の書き込みが、実は「失敗したように見えただけで、実際にはデータベース側で処理が完了していた」場合、リトライによる2回目の書き込みは、同じ在庫調整を**二重に**適用してしまう。前々巻が判定した在庫データの不整合は、まさにこの構造から生まれた可能性が高い。
### 冪等性 — 何回実行しても、結果が変わらないという性質
リトライという技法を安全に使うために欠かせないのが**冪等性(べきとうせい、idempotency、水準五: ある操作を1回実行しても、複数回実行しても、システムの状態が同じ結果になるという性質)**である。冪等性という言葉は、本シリーズ姉妹巻BOOK-0359d第四章「整形 — 冪等性という約束」でも扱われている考え方であり、総関数辞書ではFUNC-0792(冪等な再生成、idempotent regeneration)やFUNC-0730(整形冪等性検査、formatter idempotency check)に一般化されている。同巻の文脈では「同じ入力に対して整形処理を2回かけても、結果が変わらない」という性質を扱っていたが、本巻の文脈では「同じ書き込み処理を2回実行しても、システムの状態が変わらない」という、より広い意味での冪等性を扱う。
在庫調整の処理を例に、冪等性のある設計とない設計の違いを比べてみよう。
```
【冪等性のない設計(危険)】
処理内容: 「在庫数から10個を減らす」という差分の指示
1回目実行: 在庫100 → 90
2回目実行(リトライによる重複): 在庫90 → 80(意図せず二重に減ってしまう)
【冪等性のある設計(安全)】
処理内容: 「この注文ID(order-8821)による調整は、在庫を90にする」という
べき等キー(idempotency key)付きの指示
1回目実行: 注文order-8821は未処理 → 在庫を90にセットし、
「order-8821は処理済み」と記録
2回目実行(リトライによる重複): 注文order-8821は処理済みだと確認できるため、
何もせず「成功」を返す(在庫は90のまま)
```
冪等性のある設計では、処理を実行する前に「このべき等キー(この例では注文ID)は、すでに処理済みか」を確認する一手間が加わる。この一手間さえあれば、同じ処理が何度リトライされても、結果は変わらない。**リトライという技法そのものは正しい対処であり、問題はリトライではなく、リトライされる処理が冪等になっていなかったことにある**——これが、前々巻の事件から得られる、本章の核心の教訓である。
### 検算6 — 指数バックオフで、リトライの負荷集中を避ける
リトライには、もう1つ考慮すべき論点がある。障害が起きた瞬間、多数のクライアントが一斉に「もう一度試す」と動き出すと、かえって障害からの回復を妨げてしまう場合がある。この問題への対処が**指数バックオフ(しすうバックオフ、exponential backoff、水準五: リトライを実行するたびに、待ち時間を指数関数的に伸ばしていく方式)**であり、総関数辞書ではFUNC-0294(指数バックオフ、exponential backoff)に、待ち時間つきのリトライ自体はFUNC-0384(リトライ、retry with backoff)に、それぞれ一般化されている。
```
1回目のリトライ: 1秒待ってから再試行
2回目のリトライ: 2秒待ってから再試行
3回目のリトライ: 4秒待ってから再試行
4回目のリトライ: 8秒待ってから再試行
```
待ち時間を毎回2倍にしていくことで、障害発生直後の再試行の集中を和らげ、システムが回復するための時間的余裕を作ることができる。さらに実務では、この待ち時間に**ジッター(小さなランダムなばらつき)**を加えることも多い——多数のクライアントが、まったく同じタイミングで一斉にリトライすると、待ち時間を伸ばしていても、依然として「一斉再試行の波」が発生してしまうためである(この現象は次章のサーキットブレーカーとも関わる)。
### コラム — 冪等性キーの設計は、いつ・誰が発行するか
冪等性のある設計を実現するには、べき等キー(冪等性キー)を、どのタイミングで、誰が発行するかが重要になる。検算5の例では「注文ID」がべき等キーの役割を果たしていたが、注文IDそのものが処理の途中で失われてしまえば、べき等性の判定ができなくなる。実務では、リクエストを送信する側(クライアント)が、リクエストごとに一意なIDをあらかじめ発行し、そのIDをリトライの際にも変えずに使い続ける、という設計が広く使われる。この「一意なIDを発行してから処理を要求する」という手順は、本シリーズに繰り返し現れる「同一性をどう定義し、どう検算するか」という問いの一形態である。
### よくある誤解 — 「読み取り処理には冪等性を気にしなくてよい」ではない
冪等性は、書き込み処理だけの関心事だと思われがちだが、実は読み取り処理にも関わる場合がある。たとえば「在庫数を読み取って、その値に応じて次の処理を分岐する」という処理が、リトライによって複数回実行されると、1回目と2回目の間に在庫数が変化していた場合、2回とも同じ判断が下される保証がない。この種の問題は、単純な冪等性だけでなく、複数の処理の間で一貫した状態を保つ、より広い整合性の設計(第十一章で扱う分散系の話)にもつながっていく。
---
> **定着量の目安(第五章)**: 検算5の型(冪等性のない設計とある設計を、同じ処理について書き出して比較する)を、在庫調整以外の例(送金処理、メール送信、注文確定等)で3パターンほど自分で作る練習をすると定着する。あわせて、指数バックオフがなぜ有効なのかを、「一斉再試行の波を避ける」という言葉で説明できることを目安とする。
---
## 第六章: タイムアウトとサーキットブレーカー — 連鎖障害を止める(水準六)
### 「待ち続ける」ことが、次の障害を生む
前章までで、単一の機体の故障への対処(冗長化・フェイルオーバー)と、リトライを安全に行うための冪等性を見てきた。しかし、複数のサービスが互いに呼び出し合う現代のシステムでは、もう1つ厄介な現象が起こり得る——**ある1つのサービスの遅延が、それを呼び出す側のサービスにまで連鎖して広がっていく**という現象である。
たとえば、サービスAがサービスBを呼び出し、サービスBが応答に通常50ミリ秒かかるところ、何らかの理由で応答が返ってこなくなったとする。サービスAが「応答が来るまで待つ」という設計になっていた場合、サービスAの処理も止まってしまう。サービスAを呼び出すサービスも同様に止まり……という具合に、1つのサービスの不調が、まるで将棋倒しのように、システム全体に連鎖して広がっていく。この現象は**連鎖障害(れんさしょうがい、cascading failure、水準六: 1つのコンポーネントの障害が、それに依存する他のコンポーネントへと次々に連鎖して広がっていく現象)**と呼ばれる。
### タイムアウト — 「待ち続けない」という約束
連鎖障害への、もっとも基本的な防波堤が**タイムアウト(たいむあうと、timeout、水準六: 処理の応答を待つ時間に上限を設け、その上限を超えたら「失敗した」とみなして処理を打ち切る仕組み)**である。総関数辞書ではFUNC-0297(タイムアウト付き実行、timeout wrapper)、より並行処理の文脈ではFUNC-1347(キャンセルとタイムアウト)に一般化されている。
タイムアウトの値の設定には、繊細なバランスが要る。短すぎるタイムアウトは、正常に処理が完了するはずだった呼び出しまで「失敗」と誤判定してしまう。長すぎるタイムアウトは、連鎖障害への防波堤としての役割を果たせない——サービスBが実際には応答不能に陥っているのに、サービスAが30秒も待ち続けていては、その30秒の間、サービスAのリソース(スレッドや接続)が占有され続け、サービスA自身の処理能力も食いつぶされてしまう。
### 検算7 — タイムアウトの設定不備が、スレッド枯渇を招く仕組み
サービスAが、通常は50ミリ秒で応答するサービスBを、1秒あたり100回呼び出しているとする。タイムアウトが適切に設定されていれば(たとえば200ミリ秒)、1つの呼び出しが200ミリ秒でタイムアウトし、そのリソースは解放される。ところが、もしタイムアウトが30秒に設定されたままで、サービスBが応答不能に陥ったとすると、次のような計算になる。
```
1秒間に発生する呼び出し数: 100回
1回の呼び出しが占有する時間: 最大30秒(タイムアウトまで)
30秒間に蓄積される、応答待ちの呼び出し数: 100回×30秒 = 3,000件
```
もしサービスAが同時に処理できる呼び出し数(スレッド数や接続数の上限)が、たとえば500だったとすると、わずか5秒(500件分)でその上限に達し、それ以降のすべての呼び出しが「空きがない」という理由で失敗し始める。**タイムアウトの値ひとつの設定ミスが、サービスAというまったく別のシステムまで巻き込んで停止させてしまう**——これが、連鎖障害の恐ろしさである。
### サーキットブレーカー — 「もう呼び出さない」という判断
タイムアウトが「1回の呼び出しをいつ諦めるか」を決める仕組みだったのに対し、**サーキットブレーカー(さーきっとぶれーかー、circuit breaker、水準六: 呼び出し先の失敗が一定回数・一定割合を超えたとき、それ以降の呼び出しを一定時間、自動的に止めてしまう仕組み)**は、「そもそも、しばらく呼び出すこと自体をやめる」という、一段上の判断を行う。総関数辞書ではFUNC-0296(サーキットブレーカー、circuit breaker)に一般化されている。名前の由来は、電気回路の安全装置(過電流が流れたときに自動的に回路を遮断するブレーカー)から来ている。
サーキットブレーカーは、一般に3つの状態を行き来する状態機械として実装される。
```
[Closed(閉)] ─── 失敗が一定回数連続する ───▶ [Open(開)]
▲ │
│ 一定時間(クールダウン)経過
│ ▼
└──── 試験呼び出しが成功する ──── [Half-Open(半開)]
│
試験呼び出しが失敗する
▼
[Open(開)]へ戻る
```
平常時は**Closed(閉)**の状態で、呼び出しは普通に行われる。呼び出しの失敗が、たとえば「5回連続」のように一定のしきい値を超えると、サーキットブレーカーは**Open(開)**の状態に切り替わり、それ以降の呼び出しを、実際にサービスBへ送ることなく、即座に失敗として扱う(この即座の失敗は、後述の第七章「段階的縮退」の入り口にもなる)。一定時間(クールダウン期間、たとえば30秒)が経過すると、**Half-Open(半開)**の状態に移り、試しに1回だけ呼び出しを送ってみる。この試験呼び出しが成功すればClosedへ戻り、失敗すれば再びOpenへ戻る。
サーキットブレーカーの価値は、応答不能に陥っているサービスBへ、無駄な呼び出しを送り続けることをやめる点にある。これにより、サービスA側のリソースを守れるだけでなく、サービスB側にとっても、回復しようとしている最中に大量の呼び出しを浴び続けずに済む、という利点がある。
### コラム — サーキットブレーカーとリトライは、組み合わせ次第で逆効果になる
第五章で見たリトライと、本章のサーキットブレーカーは、単純に両方とも導入すればよいというものではない。もしサーキットブレーカーがOpenの状態にあるのに、呼び出し側が指数バックオフ(第五章)を無視して即座にリトライを繰り返すと、サーキットブレーカーの「呼び出しを止める」という意図が骨抜きになってしまう。実務では、サーキットブレーカーの状態そのものをリトライの判断に組み込み、「Openの間はリトライしない」「Half-Openの試験呼び出し以外は送らない」という形で、両者を協調させる設計が必要になる。
### よくある誤解 — 「タイムアウトを短くすればするほど安全」ではない
タイムアウトの値は、短ければ短いほど連鎖障害を防げるように思えるが、実際には短すぎるタイムアウトにも代償がある。正常に処理が完了するはずだった呼び出しまで、わずかな遅延(ネットワークの一時的な混雑等)によって「失敗」と誤判定されてしまうと、その誤判定に対して第五章のリトライが発動し、かえって呼び出しの総数を増やしてしまう場合がある。タイムアウトの値は、対象サービスの通常の応答時間の分布(平均だけでなく、ばらつきの大きさ)を実測したうえで、余裕を持たせて設定する必要があり、「短ければ短いほどよい」という単純な話ではない。
---
> **定着量の目安(第六章)**: 検算7の型(呼び出し頻度×タイムアウト時間から、蓄積される同時呼び出し数を計算する)を、数値を変えて3パターンほど計算する練習をすると定着する。あわせて、サーキットブレーカーの3状態(Closed・Open・Half-Open)を、自分で図に描いて説明できることを目安とする。
---
## 第七章: 段階的縮退(グレースフルデグラデーション) — 全滅ではなく部分機能で耐える(水準七)
### 「全部残すか、全部失うか」ではない、第三の道
ここまでの章は、障害そのものを起こさない・広げない・自動で切り替えるという、いわば「攻めの防御」を扱ってきた。しかし、どれほど冗長化しても、どれほどフェイルオーバーを整えても、想定を超える負荷や、複数の障害が重なる事態は起こり得る。そのときに問われるのが、**「全部を守ろうとして全滅するか、それとも一部を意図的に手放して、残りを守るか」**という判断である。
**段階的縮退(だんかいてきしゅくたい、グレースフルデグラデーション、graceful degradation、水準七: システムに障害や過負荷が発生したとき、全機能を停止するのではなく、優先度の低い機能から意図的に切り離し、中核となる機能だけを提供し続ける設計)**は、この判断を、あらかじめ設計として仕込んでおく技術である。「グレースフル(graceful、しなやかな)」という形容詞が示すとおり、障害の際に無様に全体が崩れ落ちるのではなく、あらかじめ決めた優先順位に沿って、しなやかに機能を減らしていく——これが本章のテーマであり、CATALOG(本シリーズ設計書)が本巻の主眼として掲げる技術の中心にあたる。
### 検算8 — 在庫管理システムの機能に、優先度を割り振る
段階的縮退を設計する第一歩は、システムの機能を洗い出し、優先度を割り振ることである。在庫管理システムを例に、機能を3段階の優先度に分けてみよう。
```
【優先度L0・絶対に死守する機能】
在庫数の読み取り専用表示(現在の在庫が何個あるかを見られること)
【優先度L1・書き込み系の中核機能】
発注確定・在庫調整(実際にデータを変更する処理)
【優先度L2・付随的な機能】
利用傾向のレコメンド表示・分析ダッシュボードの集計
```
負荷が平常時の水準であれば、L0・L1・L2のすべてを提供する。しかし、たとえば接続プールの使用率が閾値を超えるなど、システムに余裕がなくなってきた兆候が観測されたら、まずL2(付随的な機能)を意図的に停止し、浮いたリソースをL0・L1に回す。それでもなお負荷が高い場合は、L1(書き込み系)を一時的にキューへ溜める、あるいは受付を絞り、L0(読み取り専用表示)だけは最後まで提供し続ける。
この優先順位の割り振りには「唯一の正解」はなく、業務の性質によって変わる——たとえば決済システムであれば、L0は「支払いの受付」であり、「利用履歴の閲覧」のほうがむしろL2になり得る。重要なのは、平常時にあらかじめ優先順位を決めておくことであり、障害の真っ最中に、混乱の中で優先順位を即興で決めようとすると、判断そのものが遅れ、誤りやすくなる。
### 縮退の具体的な手段 — キャッシュ・フォールバック・機能フラグ
段階的縮退を実現する具体的な手段はいくつかある。1つは、最新のデータをその場で計算する代わりに、少し古くても構わないキャッシュ済みのデータを返す、という**フォールバック(代替経路への切替)**である。たとえば「在庫数の正確な最新値」を出すために毎回データベースへ問い合わせる代わりに、負荷が高いときだけ「1分前の値でよいのでキャッシュから返す」という切替を行う。この切替を制御する仕組みは、総関数辞書ではFUNC-0244(キャッシュ無効化、cache invalidate)が扱う「いつキャッシュを破棄し、いつ最新値を取りに行くか」という判断の、いわば裏返しにあたる——通常はキャッシュを早めに無効化して鮮度を保つところを、段階的縮退の局面ではあえてキャッシュの無効化を遅らせ、鮮度よりも可用性を優先する、という一時的な方針転換である。
もう1つの手段は、**機能フラグ(きのうふらぐ、feature flag、水準七: 特定の機能のオン・オフを、コードを書き換えずに切り替えられるようにしておく仕組み)**である。あらかじめL2の機能(レコメンド表示等)を機能フラグで囲んでおけば、障害対応の最中に、コードの変更やデプロイ(再配布)を行うことなく、その機能だけを即座に停止できる。デプロイという行為自体が、障害対応中には新たなリスクになり得るため、「コードを変えずに切り替えられる」という性質は、段階的縮退の実務において重要な価値を持つ。
### コラム — 「壊れたと気づかれない縮退」という理想
もっとも洗練された段階的縮退は、利用者が「何かが縮退している」とすら気づかない形で行われる。たとえば、レコメンド機能が停止しているあいだ、画面からレコメンド欄を丸ごと消してしまうのではなく、「よく購入されている商品」のような、あらかじめ計算済みの一般的な代替コンテンツをそっと表示しておく、という設計である。逆に、縮退したことを利用者にはっきり伝えたほうがよい場合もある——「現在、一部の機能が制限されています」という通知は、利用者の不信感を減らす効果がある一方、頻繁に表示されすぎると、逆にシステムへの信頼を損なう可能性もある。どちらが適切かは、業務の性質と利用者との関係性によって変わる、設計判断の一つである。
### よくある誤解 — 「縮退は最後の手段、めったに使わないもの」ではない
段階的縮退の仕組みは、めったに起きない大規模障害のためだけに用意しておくものだと思われがちだが、実務ではむしろ**日常的に**発動する設計にしておくほうが安全である。理由は、第四章のコラムで触れたフェイルオーバーの落とし穴と同じである——めったに発動しない仕組みは、いざというときに正しく動くかどうかが、平常時には検証されない。段階的縮退の仕組みも、たとえば「毎週決まった曜日・時間帯にL2機能を意図的に一時停止してみる」といった形で、定期的に実際に発動させておくことで、「いざというときに、本当に縮退できるか」を継続的に確認しておくことが望ましい。この発想は、第十章で扱うカオスエンジニアリングの考え方の先取りである。
---
> **定着量の目安(第七章)**: 検算8の型(自分の身近なサービスやアプリの機能を、L0・L1・L2の3段階に優先度分けする)を、2〜3個のサービスについて自分で作る練習をすると定着する。あわせて、フォールバックと機能フラグという2つの縮退手段を、それぞれ具体例とともに説明できることを目安とする。
---
## 第八章: 過負荷をさばく — キャッシュ・キュー・バックプレッシャー・レート制限(水準八)
### 負荷は、必ずしも障害ではない
ここまでの章は、主に「何かが壊れる」ことへの対処を扱ってきた。しかし可用性・信頼性工学が向き合う脅威は、故障だけではない。**想定を超える量のリクエストが、正常に動いているシステムに押し寄せる**という、いわば「成功の副作用」もまた、可用性を脅かす。セールの開始直後、話題になった直後、あるいは意図的に大量のリクエストを送りつける攻撃——本シリーズ第一巻(BOOK-0360)第二章がCIA三要素の一つとして扱う可用性は、こうした脅威も含めて成り立つ——原因が何であれ、「捌ける量を超えるリクエスト」への備えは、信頼性工学の重要な一角を占める。
### キャッシュ — 同じ計算を繰り返さない
**キャッシュ(かっしゅ、cache、水準八: 計算結果や取得済みのデータを一時的に保存しておき、同じ要求が来たときに再計算・再取得せずに済ませる仕組み)**は、過負荷対策のもっとも基本的な手段である。同じ問い合わせが繰り返し来るとき、毎回データベースまで問い合わせに行く代わりに、直近の結果を保持しておいて即座に返せば、データベースへの負荷を大きく減らせる。
ただし、キャッシュには常に「いつ古くなった値を捨てるか」という問題がついて回る。総関数辞書のFUNC-0244(キャッシュ無効化、cache invalidate)は、この「捨てるタイミング」を扱う機能素であり、より大規模な仕組みではFUNC-0750(ビルドキャッシュ無効化、build cache invalidation)のように、特定の領域に特化した無効化の仕組みも登録されている。第七章で触れたとおり、段階的縮退の局面ではキャッシュの無効化をあえて遅らせることもあるが、平常時には「新しい値が書き込まれたら、対応するキャッシュを速やかに無効化する」という規律が守られていなければ、利用者に古い情報を見せ続けてしまう危険がある。
### キュー — 一気に処理せず、順番に並ばせる
リクエストが一時的に殺到しても、システムの処理能力そのものを超えないように調整する仕組みが**キュー(きゅー、queue、水準八: 処理すべき要求を、いったん順番待ちの列に並べておき、処理能力に見合った速さで順番に取り出して処理する仕組み)**である。総関数辞書では、要求を列に加える操作がFUNC-0234(キュー投入、enqueue)、列から取り出す操作がFUNC-0235(キュー取出、dequeue)として一般化されている。
キューを使うことで、瞬間的なリクエストの殺到(バースト)を、時間方向に引き伸ばして処理できる。ただし、キューには限界がある——リクエストが処理される速さよりも、リクエストが到着する速さのほうが恒常的に速ければ、キューはいつまでも溜まり続け、いずれ待ち時間が利用者にとって許容できないほど長くなるか、キュー自体の容量が尽きる。
### 検算9 — リトルの法則で、キューに溜まる量を見積もる
待ち行列の平均的なふるまいを見積もる、よく知られた公式に**リトルの法則(りとるのほうそく、Little's Law、水準八: 定常状態にある待ち行列システムにおいて、システム内の平均的な数量Lは、到着率λと平均滞在時間Wの積に等しい、という関係式)**がある。式は次のとおりである。
```
L = λ × W
(L: システム内の平均的な要求数、λ: 到着率〈1秒あたりの到着数〉、W: 平均滞在時間〈秒〉)
```
在庫調整APIへのリクエストが、平常時は1秒あたり平均100件(λ=100)、1件あたりの処理に平均200ミリ秒(W=0.2秒)かかっているとしよう。
```
L = 100 × 0.2 = 20
```
システム内に平均して常時20件のリクエストが存在している(処理中または待機中)という計算になる。もし、このシステムが同時に処理できる上限が10件しかない設計だった場合、平均20件が滞在しようとする状況は、恒常的にキューがあふれるか、待ち時間が際限なく伸び続けることを意味する。リトルの法則は、あくまで定常状態(到着率と処理速度が長期的に釣り合っている状態)を前提とした近似的なモデルであり、瞬間的な変動までは表現できないが、「このシステムには、どれくらいの同時実行能力を備えておく必要があるか」という設計上の見積もりには、簡便で強力な道具になる。
### バックプレッシャーとレート制限 — 「受け付けない」という選択
キューが無限に伸び続けることを許してしまうと、待ち時間が実用に耐えないほど長くなるだけでなく、キューを保持するためのメモリそのものを圧迫し、別の障害を招きかねない。この事態を避けるための2つの技法が、**バックプレッシャー(ばっくぷれっしゃー、back pressure、水準八: 処理能力を超えるリクエストに対して、受付側から送信側へ「これ以上送らないでほしい」という信号を送り返す仕組み)**と、**レート制限(れーとせいげん、rate limiting、水準八: 一定時間あたりに受け付けるリクエストの数に、あらかじめ上限を設けておく仕組み)**である。レート制限は総関数辞書のFUNC-0255(レート制限、rate limiting)に一般化されている。
バックプレッシャーとレート制限の違いは、「誰が」「いつ」制御するかにある。バックプレッシャーは、受付側が自分の処理能力に応じて動的に「もう送らないで」と伝える、いわば内側からの調整である。レート制限は、あらかじめ決めた固定の上限(たとえば「1利用者あたり1秒間に10リクエストまで」)を、受付の入り口で機械的に適用する、外側からの調整である。両者は排他的ではなく、組み合わせて使われることが多い——レート制限で明らかな超過を入り口で弾きつつ、それでも内部の処理能力に余裕がなくなってきたら、バックプレッシャーでさらに絞る、という多層の防波堤を築くことができる。
### コラム — 過負荷対策と、段階的縮退はセットで設計される
本章で見たキャッシュ・キュー・バックプレッシャー・レート制限は、いずれも「押し寄せる負荷を、システムの中でどう吸収するか」という技術である。しかし、これらの仕組みにも限界があり、限界を超えたときにどうするかという問いに答えるのが、前章(第七章)の段階的縮退である。レート制限で弾かれたリクエストに対して、ただエラーを返すだけでなく、「今は混み合っているので、L2機能を一時停止して余裕を作りつつ、L0・L1だけは提供し続ける」という判断につなげることで、過負荷対策と段階的縮退は、一つの連続した設計として機能する。
### よくある誤解 — 「キャッシュを増やせば増やすほど安全」ではない
キャッシュは過負荷対策の切り札のように語られがちだが、キャッシュそのものにもメモリという有限の資源が必要であり、無制限に増やせるわけではない。また、キャッシュされたデータが古くなっていく速度(鮮度が失われる速度)と、業務が許容できる古さの限度を見極めずにキャッシュを多用すると、第七章で扱った「気づかれない縮退」どころか、「気づかれないまま古いデータで業務判断が行われる」という、新しい種類のリスクを生んでしまう。キャッシュ無効化(FUNC-0244)の設計は、過負荷対策と正確性のバランスを取る、地味だが重要な仕事である。
---
> **定着量の目安(第八章)**: 検算9の型(リトルの法則L=λ×Wを使って、システム内の平均要求数を計算する)を、到着率λと滞在時間Wの値を変えて5パターンほど計算する練習をすると定着する。あわせて、バックプレッシャーとレート制限の違いを、「誰が」「いつ」制御するかという観点で説明できることを目安とする。
---
## 第九章: SLI・SLO・エラーバジェット — 信頼性を数値の契約にする(水準九)
### 「だいたい安定してる」を、関係者全員が同じ数字で語れるようにする
ここまでの章では、可用性を高めるための個々の技術(冗長化・フェイルオーバー・リトライ・タイムアウト・段階的縮退・過負荷対策)を積み上げてきた。しかし、これらの技術をどこまで・どの水準まで積み上げるべきかは、技術だけでは決まらない。「どれくらい信頼性が高ければ十分か」という問いには、事業側の判断が必要であり、その判断を関係者全員が同じ言葉・同じ数字で共有するための枠組みが、本章で扱うSLI・SLO・エラーバジェットである。
**SLI(えすえるあい、Service Level Indicator、サービスレベル指標、水準九: サービスの信頼性を、実際に測定可能な形で定義した数値指標)**は、「何を測るか」を定める。たとえば「在庫調整APIへのリクエストのうち、200ミリ秒以内に成功応答を返せた割合」がSLIの一例になる。
**SLO(えすおー、Service Level Objective、サービスレベル目標、水準九: SLIについて、どの水準を達成することを目標とするかを定めた、内部的な目標値)**は、「どこまで測るか」を定める。たとえば「直近30日間で、SLI(200ミリ秒以内の成功率)が99.9%以上であること」がSLOの一例になる。
SLOと似た言葉に**SLA(えすえーえー、Service Level Agreement、サービスレベル合意、水準九: SLOのうち、達成できなかった場合に、契約上の返金や補償などの取り決めが結びついた、対外的な合意)**がある。SLOはあくまで内部の目標であり未達でも契約上の責任は生じないのに対し、SLAは対外的な約束であり、未達の場合には具体的な代償が発生する場合がある点が、両者の違いである。
### エラーバジェット — 「壊れてもよい枠」を、あらかじめ確保しておく
SLOが「99.9%」のように設定されていれば、その裏側には自動的に「0.1%までは許容される失敗の枠」が存在することになる。この枠を**エラーバジェット(えらーばじぇっと、error budget、水準九: SLOで許容されている「失敗してもよい枠」を、具体的な時間や回数として明示的に管理する考え方)**と呼ぶ。
### 検算10 — エラーバジェットを、実際に計算し、消費状況を追う
SLOが「直近30日間で可用性99.9%」と定められているシステムを例に、エラーバジェットを計算してみよう。30日間の総時間は30日×24時間=720時間である。
```
エラーバジェット = 720時間 × (1 − 0.999) = 720時間 × 0.001 = 0.72時間 = 43.2分
```
このシステムで、月の前半にある障害が発生し、復旧までに15分を要したとする。
```
残りのエラーバジェット = 43.2分 − 15分 = 28.2分
```
この計算により、「あと28.2分までなら、今月のSLOを守ったまま追加の障害に耐えられる」という、具体的で共有可能な数字が得られる。エラーバジェットが尽きかけている(あるいは使い切ってしまった)月には、新機能のリリースなど、新たなリスクを持ち込む変更を一時的に抑制し、信頼性の回復を優先する、という運用判断がしばしば取られる。この「エラーバジェットの残量に応じて、開発の優先順位そのものを調整する」という考え方は、SLI・SLO・エラーバジェットという枠組みが、単なる計測にとどまらず、組織の意思決定と直結する仕組みであることを示している。
### バーンレート — 消費の「速さ」にも注目する
エラーバジェットの残量だけでなく、**バーンレート(消費速度、burn rate、水準九: エラーバジェットが、通常のペースに比べてどれくらいの速さで消費されているかを表す倍率)**にも注目する必要がある。たとえば、30日分のエラーバジェットを、わずか3日で使い切ってしまうペースで障害が続いているとすれば、そのバーンレートは「通常の10倍」ということになる(30日÷3日=10倍)。バーンレートが高いということは、このままのペースでは月内にエラーバジェットを使い果たしてしまうことを意味し、早期の警報として活用できる。SLOを月末に振り返ってから対処するのではなく、バーンレートを日々監視することで、エラーバジェットが尽きる前に手を打てる——この考え方は、次巻BOOK-0367『監視と観測可能性』が扱う、日常的な計測基盤があって初めて実現できる。
### コラム — SLOは「高ければ高いほどよい」わけではない
第二章の検算2で見たとおり、可用性の「ナインを1つ増やす」ことは、指数関数的に難しくなる。99%から99.9%への改善と、99.9%から99.99%への改善では、後者のほうがはるかに大きな投資(冗長化の台数、監視の密度、対応体制の整備)を必要とする。SLOを不必要に高く設定することは、その達成のためのコストを不必要に押し上げ、他の開発に回せたはずの資源を圧迫する。「利用者が実際に困らない水準はどこか」を見極め、その水準にSLOを設定することが、エラーバジェットという考え方の本来の目的であり、「可能な限り高い可用性を目指す」こと自体が、常に正しい目標とは限らない。
### よくある誤解 — 「SLOを達成できなかった月は、失敗した月」ではない
エラーバジェットという考え方の本質は、「失敗を許容する枠を、あらかじめ正直に認めておく」ことにある。SLOを一度も割り込まない完璧な運用を目指すのではなく、あらかじめ決めた枠の中でなら失敗してもよい、という前提に立つことで、過剰に保守的になりすぎず、適切な速さで新機能をリリースし続けられる、というバランスが取れる。エラーバジェットを使い切ってしまった月があったとしても、それは「失敗した」のではなく、「あらかじめ決めた枠を使い切ったので、来月まではリスクを抑えた運用に切り替える」という、正常な運用サイクルの一部である。
---
> **定着量の目安(第九章)**: 検算10の型(SLOのパーセンテージから、期間中のエラーバジェットを時間で計算し、障害発生後の残量を追跡する)を、SLOの値や期間を変えて3パターンほど計算する練習をすると定着する。あわせて、SLI・SLO・SLAの3つの違いを、自分の言葉で説明できることを目安とする。
---
## 第十章: カオスエンジニアリングとポストモーテム — 壊して学ぶ、非難なき事後検証(水準十)
### わざと壊して、本当に耐えられるかを確かめる
第四章のコラムで、フェイルオーバーの仕組みは「めったに発動しないからこそ、いざというときに動くかどうか分からない」という落とし穴に触れた。同じ問題は、冗長化・段階的縮退・タイムアウト・サーキットブレーカーなど、本巻で扱ってきたあらゆる備えに共通する。**備えは、実際に発動させてみるまで、本当に機能するかどうか分からない。**
この問題への、いささか大胆な答えが**カオスエンジニアリング(かおすえんじにありんぐ、chaos engineering、水準十: 本番相当の環境に対して、意図的に障害を注入し、システムが設計どおりに耐えられるかを実験によって確かめる実践)**である。カオスエンジニアリングという実践は、動画配信サービス大手のNetflix社が、サーバーを意図的にランダムに停止させるツール(通称「カオスモンキー」)を開発し、実運用の環境で日常的に用いたことで広く知られるようになったとされる。この実践の核心は、「壊れないことを祈る」のではなく、「壊れることを前提に、実際に壊してみて、本当に備えが機能するかを検証する」という、発想の転換にある。
カオスエンジニアリングを安全に行うには、いくつかの原則がある。まず、実験は小さな範囲(たとえば全トラフィックのごく一部)から始め、影響範囲を限定しながら段階的に広げる。次に、実験の前に「システムはこう振る舞うはずだ」という仮説をあらかじめ立てておき、実験結果がその仮説と一致するかを検証する。そして、実験中にいつでも即座に中断できる「非常停止」の手段を、必ず用意しておく。カオスエンジニアリングは、本番環境を無計画に破壊する行為とはまったく異なる、慎重に設計された実験であるという点を、強調しておく必要がある。
### 検算11 — カオス実験の設計を、検算1の構成図に当てはめる
第一章の検算1で洗い出した、在庫管理システムの4つの単一障害点(ロードバランサ・アプリケーションサーバー・データベース・接続プール)を、冗長化(第三章)によって解消したとしよう。カオスエンジニアリングでは、この「解消したはずの」単一障害点を、実際に1つずつ意図的に落としてみて、本当にフェイルオーバー(第四章)が機能するかを確かめる。
```
実験1: アプリケーションサーバーを1台、意図的に停止する
仮説: 残りの台数で処理を継続でき、利用者への影響はゼロである
検証: ヘルスチェックが5秒以内に異常を検知し、
ロードバランサが自動的に残りのサーバーへ振り分けを切り替えるか
実験2: データベースの接続プールを、意図的に枯渇させる
仮説: サーキットブレーカーが作動し、段階的縮退によってL0機能は維持される
検証: L2機能が自動的に停止し、L0機能(在庫の読み取り表示)は
応答し続けるか
```
このような実験を、平常時に計画的に実施しておくことで、「冗長化していたはずなのに、実は予備機の設定が古くて動かなかった」「サーキットブレーカーのしきい値が、実際の障害では発動しない値になっていた」といった、机上の設計と実際の挙動のズレを、本物の事件が起きる前に発見できる。
### ポストモーテム — 非難せず、仕組みの改善に変える
障害が実際に起きたあと(カオス実験によるものであれ、本物の事件であれ)、その経緯を振り返り、記録に残す作業を**ポストモーテム(ぽすとも一てむ、postmortem、事後検証、水準十: 障害の発生から復旧までの経緯を、時系列・影響範囲・根本原因・再発防止策とともに、体系的に記録し共有する文書、およびその作成プロセス)**と呼ぶ。
ポストモーテムの実務でもっとも重視される原則が**非難なき(ノンブレーム、blameless)**という姿勢である。「誰が操作を誤ったか」を追及するポストモーテムは、当事者を萎縮させ、次第に「都合の悪い事実を報告しない」という文化を生んでしまう。これでは、第一章から本章まで積み上げてきた「弱点を正直に見つける」という姿勢そのものが崩れる。非難なきポストモーテムでは、「なぜ、その操作が誤りだと気づける仕組みがなかったのか」「なぜ、その誤りがシステム全体を止めるほどの影響を持ってしまったのか」という、**仕組み**への問いに焦点を当てる。
本プロジェクトには、非難なきポストモーテムに近い実例がすでに存在する。前々巻(BOOK-0364)第六章が扱った「緑を騙る赤」——FUNC-0278(シード付き決定的乱数、seeded RNG/mulberry32)というカードが、4回の検定に合格していたにもかかわらず、5回目で初めて言語間の不一致が発見された事件である。この事件の記録は、「なぜ最初の4回の検定が見逃したのか」という仕組みへの問い(記述検査と実行検査の違い)に焦点を当てており、誰か特定の担当者を非難する形では記録されていない。ポストモーテムという実践は、この「仕組みを直す」という姿勢を、フォレンジクスの領域から可用性・信頼性工学の領域へ、そのまま持ち込んだものだと理解できる。
### コラム — 「なぜ」を繰り返して、根本原因に近づく
ポストモーテムで根本原因を掘り下げる際によく使われる、簡便な手法に、**「なぜ」を複数回繰り返して問い続ける**という考え方がある(自動車製造業の生産現場で培われた手法に由来するとされる)。「システムが止まった」→「なぜ?」→「接続プールが枯渇した」→「なぜ?」→「リトライで同じ書き込みが重複した」→「なぜ?」→「冪等性が保証されていなかった」→「なぜ?」→「べき等キーを設計する規約が、開発の初期段階に存在しなかった」——このように問いを重ねていくことで、表面的な現象(システムが止まった)から、より根本的な仕組みの欠如(べき等キーの設計規約がなかった)へとたどり着ける。ただし、「なぜ」を機械的に5回繰り返せば必ず正しい根本原因にたどり着く、というほど単純な保証はなく、あくまで思考を掘り下げるための補助的な道具として使うのが実務的である。
### よくある誤解 — 「カオスエンジニアリングは、大企業だけの特別な実践」ではない
カオスエンジニアリングという言葉の響きから、大規模な専用ツールや、大企業の潤沢なリソースがなければ実践できないと思われがちだが、本質は「意図的に障害を注入し、備えが本当に機能するかを確かめる」という考え方そのものにある。小規模なシステムでも、たとえば「開発環境で、意図的にデータベースへの接続を一時的に切ってみて、アプリケーションがどう振る舞うかを目視で確認する」という程度の実験からでも、同じ考え方を実践できる。規模の大小にかかわらず、「壊してみるまで、備えが機能するかは分からない」という本章の核心の教訓は、あらゆる規模のシステムに当てはまる。
---
> **定着量の目安(第十章)**: 検算11の型(冗長化した要素を1つずつ選び、「これを落としたら、どの備えが発動するはずか」という仮説を書き出す)を、自分の身近なシステムについて3パターンほど作る練習をすると定着する。あわせて、非難なきポストモーテムがなぜ重要なのかを、「都合の悪い事実が報告されなくなる」という具体的な理由とともに説明できることを目安とする。
---
## 第十一章: 分散系の可用性設計 — シャーディング・クォーラム・保存則との接続(水準十一)
### データそのものを、複数台に分散させる
ここまでの章で扱った冗長化(第三章)は、主に「同じデータを持つ機体を、複数台用意する」という発想だった。しかし、データの量そのものが1台では処理しきれないほど大きくなった場合、話は少し複雑になる。**シャーディング(しゃーでぃんぐ、sharding、水準十一: 1つの大きなデータ集合を、複数の機体〈シャード〉に分割して保持し、それぞれのシャードが全体の一部を担当する設計)**は、この問題への答えであり、総関数辞書ではFUNC-0916(索引シャーディング、index sharding)に一般化されている。
シャーディングは、単なる負荷分散(第八章)とは異なる。負荷分散は「同じデータの複製」を複数台に置いて、リクエストをどれに振り分けてもよい状態を作るのに対し、シャーディングは「異なるデータの一部」をそれぞれの機体に置くため、あるデータへのリクエストは、そのデータを担当するシャードへ**正しく**振り分けられなければならない。この違いから、シャーディングには「あるシャードが停止すると、そのシャードが担当するデータだけが利用できなくなる」という、負荷分散とは異なる可用性への影響が生じる——全体は完全に停止しないが、一部のデータだけが「部分的に」利用できなくなる、という状態である。これは、第七章で扱った段階的縮退と、性質の近い現象だと理解できる。
### クォーラム — 「過半数の合意」で、部分故障の中でも動き続ける
第四章で、スプリットブレインへの対処としてクォーラムの考え方に触れた。分散したデータを複数のレプリカ(複製)として保持する設計では、クォーラムの考え方がさらに精密な形で使われる。
**N/W/Rモデル(えぬだぶりゅあーるもでる、水準十一: データをN個のレプリカに複製し、書き込みはW個以上のレプリカへの反映を待ってから成功とみなし、読み取りはR個以上のレプリカから読んで結果をまとめる、という分散データ設計の基本形)**を例に考えよう。
### 検算12 — N/W/Rモデルで、部分故障への耐性を計算する
データを5個のレプリカに複製し(N=5)、書き込みは3個のレプリカへの反映を待つ(W=3)、読み取りは3個のレプリカから読む(R=3)、という設定を考える。
```
N = 5(レプリカの総数)
W = 3(書き込みに必要な最小反映数)
R = 3(読み取りに必要な最小応答数)
W + R = 3 + 3 = 6 > N = 5
```
W+RがNを上回っているという条件は、「書き込みが反映された3個のレプリカ」と「読み取りに使う3個のレプリカ」が、必ず少なくとも1個は重なる(N=5個のうち、3個+3個を選べば、必ずどこかが重複する)ことを保証する。この重なりによって、読み取りが常に最新の書き込みを反映したレプリカを、少なくとも1つは含むことが保証される。
このN/W/R構成で、レプリカのうち2台が故障した場合を考えよう。残るレプリカは5−2=3台であり、W=3・R=3の条件をぎりぎり満たせるため、書き込みも読み取りも、まだ続行できる。しかし、もし3台が故障して残りが2台になった場合、W=3・R=3の条件を満たせなくなり、システムはこの構成のままでは書き込み・読み取りともに続行できなくなる——ここで、CAP定理(→本シリーズ姉妹巻BOOK-0119第七章「規模と分散」で扱う、一貫性・可用性・分断耐性の3つを同時には満たせないという定理)が示す、一貫性(正しいデータを返す)と可用性(応答し続ける)のトレードオフが、具体的な数字として現れる。W・Rの値を小さくすれば、より多くの故障に耐えて応答し続けられる(可用性を優先)が、読み書きの重なりが保証されにくくなり、古いデータを返してしまうリスクが増える(一貫性を犠牲にする)。
### 分断が癒えたあと — レプリカ間の整合性を、保存則で検算する
分断が起きていたレプリカ群が、ネットワークの回復とともに再び通信できるようになったとき、それぞれのレプリカが持つデータが食い違っていないかを確認する必要がある。ここで、前々巻(BOOK-0364)第五章で扱った保存則検査の考え方が、そのまま応用できる。総関数辞書のFUNC-0769(保存則検査、conservation law check)とFUNC-0770(二重消費検出、double-spend detection)は、複数のレプリカに分散した台帳(→BOOK-0359b第四章が扱う金融システムの保存則監査の実装が先行事例)が、分断からの復帰後も、mint(増加)とburn(減少)の帳尻が一致しているかを検算する。分断中に、片方のレプリカでだけ処理された書き込みが、もう片方には反映されていなかった場合、この保存則の等式が崩れ、修復が必要な不整合として検出される。
さらに、複数のレプリカの記録を時系列で束ね直す作業には、FUNC-0772(台帳時系列整合検査、ledger chronological integrity check)が、実際にどちらの値が正しいのかを数量として突き合わせる作業には、FUNC-0775(数量突合、quantity reconciliation)が、それぞれ対応する。そして、これらの検算の記録自体を、誰が・いつ・どのレプリカに対して行ったかを残す作業は、FUNC-0776(監査証跡記録、audit trail recording)に対応し、前々巻第七章が扱った証拠の連鎖(chain of custody)の考え方が、分散系の復旧作業にもそのまま引き継がれる。分断からの復帰は、単に「もう一度つながった」で終わりにできる作業ではなく、フォレンジクス(判定)の技術を借りて、正しく検算されて初めて完了する仕事なのである。
### コラム — 追記専用と巻き戻しの、両立という難題
前々巻(BOOK-0364)第五章が扱った追記専用台帳(FUNC-0993、append-only storage)は、改竄検知には強力だが、分断からの復帰時に「誤って反映された書き込みを取り消したい」という場面では、そのままでは使いにくい。過去の記録を書き換えられないという制約は、改竄検知の強みであると同時に、誤りの訂正を難しくする面もある。この難題への実務的な答えは、過去の記録を**書き換える**のではなく、誤りを打ち消す**新しい記録を追加する**——たとえば「誤って加算した10個を、あらためて減算する」という取り消しの記録を、末尾に追記する——という設計である。総関数辞書のFUNC-0996(巻き戻し、rollback/revert)は、この「過去を消さずに、打ち消しの記録で状態を戻す」という考え方に対応しており、FUNC-0994(スナップショット保存、snapshot saving)やFUNC-1146(スナップショット突合状態復元検証、snapshot restore verify)と組み合わせることで、「ある時点の状態に、検算可能な形で戻す」ことができる。
### よくある誤解 — 「レプリカを増やせば増やすほど可用性が上がる」ではない
第三章の検算4で見たとおり、単純な並列冗長化であれば、台数を増やすほど可用性は向上する。しかし、N/W/Rモデルのような分散データ設計では、話はやや複雑になる——レプリカの数Nを増やしても、書き込みに必要な合意数Wを比例して増やしてしまえば、より多くのレプリカが同時に生きていなければ書き込めない、という、かえって脆弱な構成になりかねない。分散系の可用性設計は、単純な台数の掛け算ではなく、N・W・Rという3つの数字の**組み合わせ**によって決まる、という点を押さえておく必要がある。
---
> **定着量の目安(第十一章)**: 検算12の型(N・W・Rの値を変えて、W+R>Nの条件が成り立つか、また何台の故障まで耐えられるかを計算する)を、5パターンほど自分で計算する練習をすると定着する。あわせて、シャーディングと単純な負荷分散(冗長化)の違いを、自分の言葉で説明できることを目安とする。
---
## 第十二章: なぜSREという職能が生まれたか — 理論上のメタ的推移(水準十二・終章)
### 「開発」と「運用」が、別の部族だった時代
可用性・信頼性工学、通称**SRE(えすあーるいー、Site Reliability Engineering、水準十二: ソフトウェア工学の手法を、システムの運用・信頼性維持という仕事に適用する、比較的新しい専門職・専門分野)**という職能は、最初から存在していたわけではない。長らく、多くの組織では「開発(新しい機能を作る仕事)」と「運用(作られたシステムを動かし続ける仕事)」は、別々の部門、別々のキャリアパス、時には別々の企業文化として分かれていた。
この分業には、それなりの合理性があった。開発側は「新しい機能を、できるだけ早くリリースしたい」という圧力の下で働き、運用側は「システムを、できるだけ止めずに安定させたい」という、しばしば正反対の圧力の下で働く。新しい機能のリリースは、多くの場合、変更というリスクを伴う——本巻の言葉で言えば、単一障害点になり得る新しいコンポーネントを増やしたり、想定していなかった負荷のパターンを生んだりする。運用側からすれば、「変更こそが、障害の最大の原因」であり、変更を減らすことこそが安定への近道に見える。この対立構造は、開発と運用のあいだに、しばしば緊張関係を生んだ。
### 「ソフトウェアエンジニアに、運用を設計させる」という発想の転換
SREという職能が生まれた背景には、この対立構造そのものへの、ある発想の転換があった——**運用という仕事を、人手による作業の積み重ねとしてではなく、ソフトウェア工学の対象として扱う**、という転換である。人手による手順書に頼るのではなく、本巻で扱ってきたような技術——冗長化(第三章)、フェイルオーバー(第四章)、リトライと冪等性(第五章)、タイムアウトとサーキットブレーカー(第六章)、段階的縮退(第七章)、過負荷対策(第八章)——を、あらかじめコードとして設計し、実装し、自動化しておく。そして、SLI・SLO・エラーバジェット(第九章)という数値の契約によって、「どこまで手を動かして安定させるか」「どこから先は、開発側のリリース速度を優先してよいか」という、開発と運用の間の緊張関係そのものを、感覚や立場の対立ではなく、共有された数字で調整できるようにする。
この転換の核心は、「壊れないシステムを作る」ことをあきらめ、「壊れることを前提に、壊れても致命傷にならない・早く直せる・一部の機能だけでも残せる」という設計へと、目標そのものを置き換えた点にある。本巻の第一章から第十一章までの技術は、すべてこの転換——完璧な無故障を目指すのではなく、故障を前提にした設計を積み上げる、という一貫した思想——の具体的な現れである。
### 一日停止・全システム再構成という業務との、最後の接続
本シリーズ全体の値札であった「一日停止・全システム再構成の段階判断」という特命業務に、あらためて立ち返ろう。前々巻(BOOK-0364)は、止まった後に「何が、いつ、どう壊れたか」を判定する技術を、前巻(BOOK-0365)は、止まった後に「確実に戻ってこられる」技術を、それぞれ積み上げた。本巻は、この2つとは異なる時間軸——**まだ止まっていない、平常時**に働きかける技術を積み上げてきた。
この3巻の関係を、あらためて俯瞰すると、次のような構図が見えてくる。判定(前々巻)と復旧(前巻)は、事件が起きた**後**に発動する技術である。可用性・信頼性工学(本巻)は、事件が起きる**前**に、事件そのものを起きにくくし、起きても被害を小さくするための技術である。もし本巻の技術が、入口の物語の在庫管理システムに、事件の前からきちんと組み込まれていたら——データベースが冗長化され(第三章)、フェイルオーバーが自動化され(第四章)、リトライに冪等性が備わり(第五章)、接続プール枯渇に対してサーキットブレーカーと段階的縮退が働いていたら(第六章・第七章)——「今日一日、全システムを止めてでも」という指示そのものが、そもそも必要なかったかもしれない。
ただし、本巻の技術をどれだけ積み上げても、判定(前々巻)と復旧(前巻)の技術が不要になるわけではない、という点は、正直に述べておく必要がある。どれほど冗長化しても、どれほど段階的縮退を設計しても、可用性が100%になることはない——本巻を通じて繰り返し確認してきたとおり、可用性はあくまで確率の問題であり、公表された数字や物理法則にもとづいて語れる範囲でしか、その限界を下げることしかできない。SREという職能が担うのは、「二度と壊れないようにする」仕事ではなく、「壊れる頻度と、壊れたときの被害を、設計によって継続的に小さくし続ける」仕事である。
### 講師級の視点 — SREは、なぜ「職能」として独立する必要があったのか
最後に、本巻でもっとも抽象度の高い問いに向き合おう。可用性・信頼性工学の個々の技術(冗長化・フェイルオーバー・リトライ等)は、開発チームのメンバーがそれぞれ片手間に学んでもよさそうに見える。それでも、なぜこれらの技術が「SRE」という、専任の職能・専任のチームとして独立する必要があったのだろうか。
答えの手がかりは、第一章の単一障害点の議論そのものにある——**「人」もまた、単一障害点になり得る**という洞察である。可用性・信頼性工学の技術を、開発チームの誰かが「片手間に」担当している状態は、その担当者が異動・退職・多忙になった瞬間に、これまで本巻で積み上げてきたすべての備え(冗長化の設定、フェイルオーバーの調整、サーキットブレーカーのしきい値、段階的縮退の優先順位)が、誰にも保守されないまま古びていく、というリスクを抱える。SREという職能が専任のチームとして独立する意義は、可用性・信頼性工学という仕事自体を、個人の善意や片手間の努力ではなく、**組織として継続的に担う体制**に落とし込む点にある——これは、前々巻(BOOK-0364)第九章が扱った職務分掌・体制設計という考え方が、判定(フォレンジクス)の領域から、可用性・信頼性工学の領域へ、そのまま引き継がれた形だと理解できる。
本シリーズの一本道(→CATALOG_情報防衛と復旧シリーズ.md§1)は、検知の前提(第八巻)、判定(前々巻)、対応の背骨(第四巻)、復旧と再構成(前巻・本巻・第十二巻)、そして制度で締める(第九巻)という構成をとる。本巻が担った「構成し直し」の仕事は、この一本道の中で、唯一「事件が起きる前」に働きかける技術群であり、だからこそ、他のどの巻よりも、日々の地道な保守と、専任の職能による継続的な手入れを必要とする——これが、可用性・信頼性工学という一冊を締めくくる、講師級の結論である。
---
> **定着量の目安(第十二章)**: 開発と運用が対立しがちな理由、そしてSREという職能がその対立を「数字の契約(SLI・SLO・エラーバジェット)」で調整するという発想を、自分の言葉で説明できるようになるまで、2〜3回読み返すとよい。あわせて、本巻第一章から第十一章までの技術を、「事件が起きる前に働きかける技術」という共通点で振り返り、前々巻・前巻(判定・復旧)との違いを、自分の言葉で整理する練習をすると、本巻全体の定着が確かなものになる。
---
## 三つの実践解(§16.21) — 手元の環境だけでできる、安全な実践
理論を、実際に手を動かして確かめる方法を三つ紹介する。いずれも実在システムへの侵入や、危険な操作を必要としない、安全な実践解である。
1. **身近なサービスの単一障害点を洗い出す実践**: 自分がよく使うアプリやサービスを1つ選び、第一章の検算1の型で、簡単な構成図(利用者→アプリ→データ保存先、程度の粗さでよい)を描き、「これが1つ壊れたら全体は止まるか」を各要素に問うてみる。あわせて、そのサービスが実際に短時間停止した経験があれば、その原因が単一障害点だったのかどうかを推測してみると、理解が深まる。
2. **可用性の計算を、自分で手を動かして確かめる実践**: 検算2〜検算4で使った「稼働率のかけ算・割り算」の計算を、電卓や表計算ソフトを使って、自分で数値を変えながら10パターンほど計算してみる。特に、直列構成(掛け算で下がる)と並列構成(足し合わされる方向で上がる)の違いを、自分で作った数値例で体感すると、冗長化の効果が実感として残る。
3. **架空のポストモーテムを、自分で1本書いてみる実践**: 自分の身の回りで実際にあった小さな失敗(遅刻、忘れ物、作業のやり直し等、深刻でないものでよい)を1つ選び、第十章の型(時系列・影響範囲・根本原因・再発防止策)に沿って、非難なきポストモーテムを書いてみる。「なぜ」を3〜4回繰り返して根本原因を掘り下げる練習も、あわせて行うとよい。この実践は、実在システムへの操作を一切必要とせず、安全に本章の考え方を体得できる。
---
## まとめ — 止まらないためではなく、止まっても致命傷にしないための一本道
本巻では、「たった1台が全部を道連れにする」という単一障害点(第一章)の発見から始まり、可用性を数字で語る物差し(第二章)、予備を用意する冗長化の基本形(第三章)、予備へ自動で切り替えるフェイルオーバー(第四章)、再試行しても壊れない冪等性の設計(第五章)、連鎖障害を止めるタイムアウトとサーキットブレーカー(第六章)、全滅を避ける段階的縮退(第七章)、押し寄せる負荷をさばくキャッシュ・キュー・レート制限(第八章)、信頼性を数値の契約にするSLI・SLO・エラーバジェット(第九章)、壊して学ぶカオスエンジニアリングと非難なきポストモーテム(第十章)、複数台に分散したデータの整合性まで含めた分散系の設計(第十一章)、そして最後に、なぜSREという職能がこの世に生まれる必要があったのかという理論上のメタ的推移(第十二章)までをたどってきた。
深夜3時に止まった在庫管理システムの物語に、もう一度戻ろう。1台しかなかったデータベースと接続プール(第一章の単一障害点)、その可用性がどれほどの年間停止時間を意味していたか(第二章)、もし予備を並列に用意していたら可用性はどこまで改善したか(第三章)、その予備へ自動で切り替える仕組みがあれば、手作業の30分ではなく25秒でMTTRが済んでいたはずだったこと(第四章)、リトライが引き起こした二重書き込みは、冪等性さえ備わっていれば起きなかったこと(第五章)、接続プール枯渇の連鎖を、タイムアウトとサーキットブレーカーが止められたはずだったこと(第六章)、それでも足りなければ、L2機能を手放してL0機能だけは守り抜く段階的縮退という選択肢があったこと(第七章)——この一連の「もしあれば」を、本巻はすべて、具体的な技術と検算として示してきた。
判定の結果は前々巻(BOOK-0364)が、戻ってくる力は前巻(BOOK-0365)が、それぞれ担った。本巻が担ったのは、次に同じ夜が来ないよう、あるいは来たとしても、丸一日ではなく数分・数秒で乗り越えられるよう、平常時から仕込んでおく設計である。「一日停止・全システム再構成の段階判断」という特命業務の「構成し直し」の段階は、この一冊で、判定・復旧とあわせて、ひとまずの完結を見る。
---
## 章末: 可用性計算の検算図と、まとめの階段図
まず、第二章〜第四章で積み上げた可用性計算の流れを、図で振り返る。
```
単体のデータベース(可用性99.5%) ─ 年間停止時間 約43.8時間
↓ 第三章: 並列冗長化(もう1台追加)
並列2台構成(可用性99.9975%) ─ 年間停止時間 約13分
↓ 第四章: 自動フェイルオーバー(MTTRを0.5時間→25秒へ)
MTBF=720時間・MTTR=25秒の構成(可用性99.999%) ─ 年間停止時間 約5.3分
```
続いて、本巻全体の歩みを階段図としてまとめる。
```
[水準十二] なぜSREという職能が生まれたか
開発と運用の対立を、数字の契約(SLI/SLO)で調整する発想の転換
▲
│ 個々の技術を、専任の職能・体制へ落とし込む
[水準十一] 分散系の可用性設計
N=5・W=3・R=3のクォーラムと、保存則検査による分断後の整合性検算
▲
│ データそのものを複数台に分散させたときの可用性
[水準十] カオスエンジニアリングとポストモーテム
わざと壊して備えを検証し、非難なく仕組みを直す
▲
│ 備えは、発動させてみるまで機能するか分からない
[水準九] SLI・SLO・エラーバジェット
SLO99.9%・30日=エラーバジェット43.2分(検算10)
▲
│ 信頼性を、関係者共有の数字の契約にする
[水準八] 過負荷をさばく設計
リトルの法則L=λ×W=100×0.2=20(検算9)
▲
│ 故障でなく、成功の副作用としての過負荷に備える
[水準七] 段階的縮退(グレースフルデグラデーション)
L0・L1・L2という優先度で、全滅ではなく部分機能を残す(検算8)
▲
│ 全部を守るか全部失うかではない、第三の道
[水準六] タイムアウトとサーキットブレーカー
Closed→Open→Half-Openという3状態で連鎖障害を止める
▲
│ 1つの遅延が、将棋倒しのように広がるのを止める
[水準五] リトライと冪等性
02:59:03の二重書き込み(BOOK-0364)は冪等性の欠如が原因
▲
│ 「もう一度試す」を、安全に行うための設計
[水準四] フェイルオーバー
MTTR0.5時間→25秒で可用性99.93%→99.999%(検算5)
▲
│ 予備がいても、切り替わらなければ意味がない
[水準三] 冗長化の基本形
並列2台で可用性99.5%→99.9975%(検算4)
▲
│ 直列は掛け算で下がり、並列は足し合わされて上がる
[水準二] 可用性を測る物差し
99.9%の年間停止時間は約8.8時間(検算2)
▲
│ 「だいたい落ちない」を数字で語る
[水準一] 単一障害点(SPOF)とは何か
在庫管理システムの構成図に4つのSPOFを発見(検算1)
横の広がり:
[水準四] スプリットブレイン ←(対処)→ クォーラム(過半数の合意)
[水準六] タイムアウト(1回の呼び出しの諦めどき) ←(対をなす)→ サーキットブレーカー(しばらく呼ばない判断)
[水準九] SLO(内部目標) ←(区別)→ SLA(対外的な合意・違反時の代償あり)
現在のフロンティア(第十二章の視点):
開発と運用という2つの部族の対立が、SLI・SLO・エラーバジェットという
共有の数字によって調整可能になったことが、SREという職能の独立を後押しした
※本巻は理論上のメタ的推移として、この転換を講師級の視点で扱う。
前巻(情報防衛と復旧シリーズ): BOOK-0365(水準一〜十二・バックアップと災害復旧
─「戻ってこられるか」を扱う。本巻は「そもそも止まりにくくする」を扱う表裏の関係) ─────▶
次巻(情報防衛と復旧シリーズ): BOOK-0367(監視と観測可能性
─本巻第九章のSLI/SLOを実測するための、ログ・メトリクス・トレースの計測基盤) ─────▶
```
---
## 参照文献(標準・原著・本プロジェクト内アンカー)
1. Google社が公開しているSRE(Site Reliability Engineering)に関する一連の技術書・技術記事群(SLI・SLO・エラーバジェットという枠組みの整理・第九章)。本巻はこれらの概念の要旨のみを教材として要約しており、原著の文章を逐語的に引用するものではない。
2. Little, J. D. C. *A Proof for the Queuing Formula: L = λW*, Operations Research誌, 1961年公表(リトルの法則・第八章検算9)。
3. Netflix社の技術ブログ・公開資料群に見られる、カオスエンジニアリング(通称カオスモンキー)の実践に関する記述(意図的な障害注入によるレジリエンス検証の考え方・第十章)。
4. 分散システムにおけるクォーラム・N/W/Rモデル、CAP定理に関する、大学・実務向けの標準的な教科書群(第四章・第十一章)。
5. 本プロジェクト内アンカー: gakumon/BOOK-0364_情報防衛と復旧_第5巻_フォレンジクスとログ解析.md(判定の技術・入口の物語の起点・第五章のログ引用・第十章のFUNC-0278事件)、gakumon/BOOK-0365_情報防衛と復旧_第6巻_バックアップと災害復旧.md(前巻・戻ってこられる力)、gakumon/BOOK-0359b_Editor創造大全_第2部_金融システムの創造.md(保存則監査の実装・第十一章)、gakumon/BOOK-0359d_Editor創造大全_第4部_開発ツールの創造.md(冪等性という約束・第五章)、gakumon/BOOK-0070_情報派生_ネットワーク_第1巻.md・BOOK-0119_情報派生_ネットワーク_第2巻.md(冗長経路・CAP定理・第三章・第十一章)、outputs/func_dict_index.json(FUNC-ID実名確認の索引)。
---
(本冊子は情報防衛と復旧シリーズ BOOK-0366。全12巻(BOOK-0360〜0371)のうち第7巻(可用性・信頼性工学)。前巻BOOK-0365『バックアップと災害復旧』が「戻ってこられるか」を、本巻は「そもそも止まりにくくする・止まっても致命傷にしない」を扱う、表裏の関係にある一冊。次巻BOOK-0367『監視と観測可能性』では、本巻第九章が扱うSLI/SLOを実測するための計測基盤を扱う予定。CATALOG_情報防衛と復旧シリーズ.md・GAKUMON_UNIVERSE.md進捗台帳を参照。安全枠(§16.18)遵守: 本巻には実在システムへの侵入手順・動作するエクスプロイト・可用性を意図的に奪う攻撃の実行手順は一切含まれない。)
# BOOK-0366 情報防衛と復旧シリーズ 第7巻: 可用性・信頼性工学(SRE) — 止まらないためではなく、止まっても致命傷にしないための設計