はじめに
アプリケーションを書いているとき、サーバーはたいてい「1台」です。ローカルの開発環境も、最初にデプロイした本番も、1台。それで動いているうちは、何も問題がないように見えます。
問題が顕在化するのは、その1台が落ちたとき でした。
インフラを見る立場になると、「サーバーが落ちてもサービスが止まらないようにする」という要求が突きつけられます。しかも厄介なことに、その対策はインフラの中だけで完結しません。アプリケーションの書き方まで変わります。
この記事では、単一障害点を見つける → ロードバランサーで冗長化する → オートスケーリングで自動化する → アプリ側の制約に対処する までを1本にまとめました。手順書ではなく、設計の勘所として読んでいただければと思います。
このシリーズでは「ネットワークの仕組み」「マネージドサービスの考え方」も解説しています。あわせて読むと全体像がつかめます。
この記事で分かること
- 単一障害点(SPOF)を見つける視点が身につく
- 「AWS が冗長化してくれるサービス」と「自分で設計するサービス」を見分けられる
- ロードバランサーの本質が、振り分けではなくヘルスチェックだと分かる
- ロードバランサーを入れてもエラーがゼロにならない理由が説明できる
- なぜアプリをステートレスに書かなければならないのかが腹落ちする
第1章:まず「ここが落ちたら終わり」を探す
可用性の設計は、機能を足すことから始まりません。「ここが止まったら、システム全体が止まる箇所」を探すこと から始まります。これを SPOF(Single Point Of Failure:単一障害点) と呼びます。
構成図を描いて、ひとつずつ指差しながら「これが落ちたら?」と問うてみてください。
サーバーが1台ずつなら、どちらも SPOF です。ここを解消していくのが可用性設計でした。
「これは本当に SPOF なのか」を調べる癖
ここで一つ、実務で効く視点があります。構成図の上では 1つの箱にしか見えないのに、実は裏で冗長化されている サービスが存在します。
たとえば、インターネットへの出入り口となるゲートウェイや、ロードバランサー自体。これらはマネージドサービスとして提供されており、AWS 側が可用性を担保してくれています。利用者が冗長化を考える必要はありません(考えることもできません)。
サービスごとに、可用性の考え方は次のように分かれます。
| 分類 | 具体例 | 利用者がすること |
|---|---|---|
| AWS 側で冗長化済み | ロードバランサー、オブジェクトストレージ | 任せる |
| 機能として選べる | マネージドDB の冗長化オプション | 使うかどうか判断する |
| 自分で設計する | 仮想サーバー(EC2) | 複数台構成にする |
新しいサービスを使うときは、「その可用性は、どこまでサービス側が面倒を見てくれるのか」 を必ずドキュメントで確認する癖をつけましょう。そのうえで「標準の担保レベルで、うちのビジネス要件を満たせるか?」をチームやステークホルダーに問いかけられると、一段上の議論ができます。
第2章:ロードバランサーがしていること
Web サーバーの SPOF を解消する方法は単純です。複数台にして、リクエストを振り分ける。その振り分け役が ロードバランサー(LB) です。
ただ、LB の価値は「振り分け」だけではありませんでした。むしろ実務で効いてくるのは、次の機能です。
ヘルスチェック ― 壊れたサーバーを外す
LB は、配下のサーバーに定期的にリクエストを投げ、正常に応答するかを確認しています。これが ヘルスチェック です。
デプロイをミスしてアプリが 500 を返すようになった。ディスクが埋まってプロセスが落ちた。そんなとき、壊れたサーバーを自動的に切り離し、正常なサーバーにだけリクエストを送ってくれます。復旧すれば、また自動的に戻します。
設定できるのは、主にこの3つです。
| 設定 | 意味 | 一般的なデフォルト |
|---|---|---|
| チェック間隔 | 何秒ごとに確認するか | 30秒 |
| 異常のしきい値 | 何回連続で失敗したら切り離すか | 2回 |
| 正常のしきい値 | 何回連続で成功したら復帰させるか | 5回 |
切り離しは早めに、復帰は慎重に。これがセオリーです。壊れたサーバーにリクエストを送り続けるのは避けたい。一方で、まだ不安定なサーバーを急いで戻すと、また落ちて振り出しに戻ります。デフォルト値(2回 / 5回)はこの思想を反映しています。
切り離しは「瞬時」ではない
ここは誤解しやすい点でした。サーバーが壊れた瞬間に切り離されるわけではありません。
「10秒間隔で、2回連続失敗したら切り離す」設定なら、壊れてから切り離されるまで最大で20秒ほどかかります。その間、そのサーバーに振り分けられたリクエストはエラーになります。
つまり、LB を入れてもエラーがゼロになるわけではない のです。「エラーが出続ける状態」を「短時間のエラーで済む状態」にするのが LB だと理解すると、期待値がずれません。検知を速くしたければ間隔を短くできますが、その分ヘルスチェックのリクエスト回数が増えます。トレードオフです。
ドレイン ― 処理中のリクエストを守る
もう一つ、地味ですが重要な機能があります。サーバーを意図的に外すとき(デプロイ時など)、LB は 即座に接続を断ち切りません。処理中のリクエストが終わるのを一定時間待ってから外します。これを ドレイン(draining) と呼びます。
デフォルトは 300 秒(5分)程度です。「デプロイに時間がかかるな」と思ったら、この待ち時間かもしれません。逆に、長時間かかる処理を持つサービスでこの値が短すぎると、処理中のリクエストが途中で切断されます。
第3章:オートスケーリング ― 台数を自動で増減する
複数台にしたら、次は「何台にするか」という問題が生まれます。アクセスが増えれば足りず、減れば無駄です。
これを自動化するのが オートスケーリング です。「平均 CPU 使用率が 50% を超えたら増やす、下回ったら減らす。ただし最小2台、最大6台」といったルールを決めておくと、そのとおりに台数が変わります。
用語を整理しておきます。台数を横に増減 するのが スケールアウト/スケールイン。サーバーのスペック(CPU やメモリ)を上下 させるのが スケールアップ/スケールダウン。会話で混同しやすいので、議論の前に揃えておくと安全です。
「サーバーを増やしても、LB がボトルネックにならないのか」という疑問はもっともですが、LB 自身もリクエスト量に応じて裏で伸縮しています。ここは任せて大丈夫です。
第4章:ここからがアプリエンジニアの本番
さて、ここまではインフラの話でした。ですが オートスケーリングを導入した瞬間、アプリケーションの書き方に制約が生まれます。ここが本題です。
制約1:同じユーザーが同じサーバーに来るとは限らない
ロードバランサーがリクエストを振り分ける以上、同じユーザーの1回目と2回目のリクエストが、別のサーバーに届く可能性があります。
これが何を意味するか。たとえばファイルアップロード機能で、アップロードされたファイルをそのサーバーのローカルディスクに保存したとします。
2回目のリクエストがサーバーBに届いた瞬間、「さっきアップロードしたファイルが見つかりません」 となります。1台で動かしていたときには絶対に起きなかったバグです。
制約2:サーバーはいつでも消える
オートスケーリングは、負荷が下がればサーバーを 勝手に終了させます。そのサーバーのディスクにあったものは、一緒に消えます。ログも、アップロードされたファイルも、キャッシュも。
答えは「状態を外に出す」
この2つの制約への答えは同じです。サーバーに状態を持たせない。これを ステートレス な設計と呼びます。
| サーバーに持たせがちなもの | どこに置くか |
|---|---|
| アップロードされたファイル | オブジェクトストレージ(S3 など) |
| セッション情報 | 外部のキャッシュストアや DB |
| アプリのデータ | マネージドDB |
| ログ | ログ収集基盤やオブジェクトストレージ |
| ソースコード | Git(起動時に自動デプロイ) |
すべてのサーバーが同じ外部リソースを見にいくので、どのサーバーにリクエストが届いても結果は同じになります。そして、サーバーが1台消えても何も失われません。
この発想を突き詰めると、「サーバーは使い捨てられるべきもの」 という結論になります。壊れたら直すのではなく、捨てて新しく作る。ローカル1台前提のコードをそのまま複数台構成に載せると、再現しづらいバグに悩まされます。LB を入れる前に、アプリがステートレスかどうかを点検してください。
第5章:もう一つの軸 ― 物理的に離す
サーバーを2台に増やしても、その2台が 同じ建物のラックに並んでいたら、その建物が停電したときに両方止まります。
AWS はこの問題に、アベイラビリティゾーン(AZ) という単位で答えています。同じリージョン(地理的エリア)の中に、物理的に離れた複数のデータセンター群があり、それぞれが AZ です。
複数台置くなら、必ず AZ をまたいで配置する。これを マルチAZ と呼びます。
「AZ をまたぐデメリットは?」とよく聞かれますが、実質ほとんどありません(AZ 間の通信に若干の課金が発生する程度)。2台以上置くなら、2つの AZ に分散させる。 覚えておくだけで守れる、コストパフォーマンスの高い設計原則です。
まとめ:可用性設計 チェックリスト
- 可用性設計は SPOF(ここが落ちたら終わる箇所)を探すこと から始まる
- サービスは「AWS が冗長化済み」「機能として選べる」「自分で設計する」に分かれる
- ロードバランサーの本質は振り分けよりも ヘルスチェックによる自動切り離し
- 切り離しは瞬時ではない。検知までの数十秒はエラーが出る
- ドレイン は処理中リクエストの完了を待つ仕組み。短すぎると切断される
- 台数の増減=スケールアウト/イン、スペックの上下=スケールアップ/ダウン
- LB を入れた瞬間、同じユーザーが同じサーバーに来る保証は消える
- オートスケーリング下では、サーバーはいつでも消える
- 答えは ステートレス設計。ファイル・セッション・データ・ログを外に出す
- 複数台置くなら AZ をまたぐ(マルチAZ)