Webサービス負荷分散設計:成長しても破綻しないスケールと障害設計の実務
負荷分散は「トラフィックを均等に配る仕組み」として語られがちですが、実務で効いてくるのは均等性そのものよりも「落ち方を制御できるか」です。ピークを越えた瞬間に全面停止するのではなく、影響を局所に閉じ、縮退しながら継続し、復旧を速くする。ここまで含めて初めて、負荷分散はアーキテクチャとして価値を持ちます。台数や方式の話に入る前に、まず「何を守るために分散するのか」を定義しておくと、設計の投資先がぶれにくくなります。
また、負荷分散は入口のロードバランサだけで完結しません。入口で綺麗に配っても、内部で接続プールが枯れれば遅延が連鎖し、外部APIが詰まれば待ちが増幅します。つまり、分散の設計は「LBの設定」ではなく「ボトルネックの局所化」と「観測→判断→制御」を全層で揃える作業です。どの層が飽和しているかを見誤ると、増やしたはずの冗長性が逆に障害を増幅することすらあります。
本記事では、SLOを起点に「何を許容し、何を許容しないか」を言語化し、その上でL4/L7、ヘルスチェック、セッション、オートスケール、キャッシュ、DB分散、フェイルオーバー、可観測性までを一続きの設計として整理します。結論は特定の構成パターンではなく、状況が変わっても判断を再現できる設計の軸です。読み終えた時に「次に何を測り、どこに手当てを入れるべきか」が自分のサービスに当てはめて説明できる状態を狙います。
1. Webサービス負荷分散の目的を定義する
負荷分散は「均等配分」の話に見えますが、最初に決めるべきは「何を守るために分散するのか」です。目的が曖昧なまま冗長化を増やすと、構成は豪華になるのにSLOは守れず、障害時は切り分けが難しくなり、運用も重くなります。ここで目的を言語化すると、入口・アプリ・DB・キャッシュのどこに投資し、どの設計を後回しにしてよいかが自然に決まります。
1.1 Webサービスにおける「落ちない設計」の意味
「落ちない」とは、サーバが停止しないことではなく、ユーザー体験としての失敗が許容範囲に収まり、失敗しても復旧が速く、影響範囲が局所で止まる状態を指します。たとえば一部ノードが落ちても他で捌ける、依存サービスの不調時は機能を縮退して致命傷を避ける、障害時に切り戻しができる、という状態はすべて「落ちない設計」に含まれます。負荷分散はこの「局所化と継続」を実現する中心的な道具であり、単に台数を増やすよりも、落ち方を制御する能力の方が重要になる場面が多いです。
また、落ちない設計はピーク耐性だけでは成立しません。平常時の小さな劣化が積み上がり、スパイクと重なった瞬間に落ちることがほとんどです。したがって平常時に兆候を観測し、部分劣化を隔離し、必要なら縮退する設計が重要です。負荷分散はアーキテクチャであると同時に運用設計であり、「壊れても戻れる」ことを目標に置くと、過剰な冗長化や誤った最適化を避けやすくなります。
1.2 WebサービスのSLOと負荷分散の関係
SLOは負荷分散設計のゴールを具体化します。SLOが曖昧だと「とりあえず冗長化」になり、ヘルスチェックもスケールも過不足が起きます。たとえば「可用性99.9%」「p95遅延300ms」「5xxエラー率0.1%以下」といった目標があると、設計は「どの障害まで許容し、どの障害は許容しないか」「守れないときはどう縮退するか」という現実的な議論になります。ここが揃うほど、負荷分散は“構成図の正しさ”ではなく“運用可能な防衛線”として機能します。
SLOは投資先の優先順位も決めます。遅延SLOが厳しいなら入口やキャッシュ、依存隔離に投資し、可用性SLOが厳しいならマルチAZやフェイルオーバー、復旧訓練に投資する、といった整理が可能になります。守るべき指標を短く固定すると、設計・実装・監視の会話が揃い、異なるチームが同じ地図で議論できる状態を作れます。
・可用性(Availability)
・p95/p99遅延(Latency)
・エラー率(5xx/4xxの比率)
・スループット(RPS、同時接続)
・飽和指標(待ち行列長、接続数、スレッド枯渇)
2. Webサービス負荷分散アーキテクチャの全体像
ここでは、負荷分散を入口の話だけに閉じず、Webサービス全体の構造として捉え直します。なぜなら、入口で均等に配っても内部が詰まれば全体は遅くなるからです。どの層で何を分散し、どの層で何を守るかを整理すると、設計が「足し算」ではなく「ボトルネックに対する狙い撃ち」になります。
2.1 Webサービス入口と内部構成の分離
入口は外向きの統制(TLS終端、ルーティング、WAF、レート制限、DDoS対策)を担い、内部は処理の分担(アプリ、キャッシュ、DB、キュー)でボトルネックを局所化します。入口と内部の責務が混ざるほど、障害時の切り分けと復旧が難しくなり、結果として「落ちない設計」から遠ざかります。入口と内部の分離は、技術的に美しいというより、運用の判断点を分かりやすくするための設計だと捉えると実務で役立ちます。
ただし入口を賢くしすぎると、設定ミスが全ユーザー影響になる単一障害点になり得ます。逆に入口が弱すぎると、悪意あるトラフィックやスパイクが内部へ直撃し、内部のどこかが折れて雪崩れます。入口と内部の分離は「どこまで入口で守るか」という配分の設計でもあるため、SLOと運用体制(監視・変更管理・切り戻しの速さ)を前提に決める必要があります。
2.2 典型的なWebサービス構成パターン
典型構成は「入口(LB)→ アプリ(水平スケール)→ キャッシュ → DB」ですが、現実には非同期処理(キュー)、検索、外部API連携などが入り、依存関係が増えます。負荷分散は入口だけの話に見えますが、アプリが無状態でスケールできるか、DBが分散に耐えられるか、キャッシュでスパイクを吸えるかで決まります。入口が優秀でも内部が詰まれば、遅延とエラーは増え続けますし、誤ったスケール操作で状況を悪化させることもあります。
層ごとに分散手段が違う点が重要です。LBは入口の分散、キャッシュは読みの分散、DBは読み書き分離やシャーディング、外部APIはタイムアウトと隔離、といった具合です。さらに、キューはスパイク吸収と処理の分離、検索は別系統のスケールと運用、というように、追加されるサブシステムごとに「分散の目的」と「破綻パターン」が変わります。どの層がボトルネックかを観測できる設計がないと最適化が的外れになり、アプリを増やしてもDBで落ちる、といった事故が起きます。
| 層 | 代表要素 | 分散手法の方向性 |
|---|---|---|
| 入口/LB | L4/L7, WAF | ルーティング、レート制限、TLS終端 |
| アプリ | Web/API | 水平スケール、無状態化、キュー分離 |
| DB | RDB/NoSQL | 読み書き分離、レプリカ、シャーディング |
| キャッシュ | Redis, CDN | TTL、stale戦略、無効化設計 |
| 外部API | 決済/通知 | タイムアウト、サーキットブレーカ、隔離 |
| キュー/非同期 | SQS/Kafka/Redis Queue | バッファリング、リトライ設計、DLQで隔離 |
| 検索/分析 | Elasticsearch/ClickHouse | 別系統スケール、最終的整合性の許容 |
2.3 ボトルネックがWebサービス全体を決める
負荷分散が効かない典型は「最も遅い層が全体を決める」状態です。入口を増やしてもDBが詰まれば遅延は改善しませんし、アプリを増やしても外部APIが遅ければ待ちが増えます。したがって負荷分散設計の第一歩は「分散する対象を間違えない」ことです。観測が弱いと、最も目立つ層(LBやアプリ)に手を入れて、原因はDBだった、というミスが起きやすくなります。
ボトルネック設計はスケール設計と一体です。どの指標が飽和したらどの層を増やすのか、増やしてはいけないのかを決めます。たとえばDB接続数が飽和しているならアプリ増加は逆効果になり得ますし、外部APIが詰まっているならアプリ増加は待ちの増幅になります。ボトルネックの見誤りが、負荷分散を「悪化装置」に変えるため、以降の章でも常に「観測→判断→制御」の順で考えます。
3. WebサービスにおけるL4・L7負荷分散の違い
L4とL7の違いは、単なるOSIの知識ではなく「どこで制御するか」「どこで観測するか」の設計差です。L7が万能というより、L7は制御点を入口へ寄せやすく、L4は単純さと性能を得やすい、という性格があります。SLOと運用能力に合わせて、適切に使い分けます。
3.1 Webサービス通信層での役割差
L4はIP/ポートなどトランスポート層で振り分けるため、シンプルで高速になりやすいです。L7はHTTPヘッダやパスなどアプリ層で振り分けられるため、ルーティングの自由度が高く、カナリア、パスベース分割、APIと静的配信の分離などができます。どちらが優れているかではなく、どこで制御をしたいかで選びます。特に「リリースの段階導入を入口でやりたいか」「特定パスだけ別ターゲットへ流したいか」は、L7を選ぶ強い理由になります。
ただしL7は便利な分だけ設定が複雑になりやすく、誤設定が全体障害になりやすい点に注意が必要です。一方L4は単純な分、可視性や制御の面で別の仕組み(アプリ側のルーティングやサービスメッシュ)が必要になる場合があります。L4/L7の差は性能より「運用で扱える制御点をどこに置くか」の問題として捉えると、設計と体制のミスマッチを減らせます。
3.2 TLS終端位置がWebサービス設計を左右する
TLS終端をどこに置くかは、負荷分散設計の分岐点です。入口で終端すれば、内部の観測とルーティングは容易ですが、入口が重要ポイントになります。アプリまでTLSを通すとエンドツーエンド暗号化は強くなりますが、L7的な可視性や制御が弱くなりやすく、WAFやレート制限の設計が変わります。また、証明書更新の運用負荷や、mTLSを使う場合の責務分担(入口終端+内部mTLSなど)も変わります。
TLS終端位置はセキュリティだけでなく、観測と制御を左右します。例えば入口終端ならHTTPメトリクスが取りやすく、ルール適用も一箇所で済みますが、入口障害の影響が大きくなります。逆にパススルーは入口の役割が軽くなりますが、アプリ側で観測と制御を肩代わりする必要が出ます。SLOと運用体制を踏まえ「どこに責任を置くか」を決めるのが実務的です。
| 比較観点 | L4 | L7 |
|---|---|---|
| 制御粒度 | 粗い(接続単位) | 細かい(リクエスト単位) |
| 可視性 | 低め | 高い(HTTP理解) |
| コスト | 低めになりやすい | 高めになりやすい |
| 運用難易度 | 低〜中 | 中〜高 |
| セキュリティ制御 | 入口での制御が限定 | WAF/レート制限を適用しやすい |
| ルーティング拡張 | 原則難しい | パス/ヘッダ/ホストで柔軟 |
4. Webサービス負荷分散方式の選定基準
方式選定は「均等に配る」話ではなく「偏りと運用をどう扱うか」の話です。ラウンドロビン、最小接続、重み付けはそれぞれ向き不向きがあり、トラフィック特性とリリース戦略で最適解が変わります。方式は最後に決めるのではなく、SLOと観測設計と一緒に決める方が破綻しにくくなります。
4.1 ラウンドロビンはWebサービスに十分か
ラウンドロビンは最もシンプルで、ノード性能が揃い、リクエストの重さが近いなら十分に機能します。ただし現実には、処理時間のばらつき、外部API待ち、クエリ偏りがあり、均等に配っても負荷は均等になりません。つまりラウンドロビンは「配分は均等」でも「負荷は均等」を保証しません。均等配分が成立するのは、負荷が均一に近いときに限られます。
だからこそ、ラウンドロビンが成立する条件を言語化します。成立しないなら、方式を変えるのではなく、重いパスの隔離、キュー導入、キャッシュ強化など別の手当てが必要なことも多いです。方式選定をLB設定の話に閉じず、トラフィック特性を前提にしたシステム設計として捉えると、安易な方式変更で運用を複雑化させる失敗を減らせます。
4.2 最小接続方式の適用ケース
最小接続は、処理時間のばらつきや長時間接続がある場合に偏りを抑えやすい方式です。接続数が多いノードへ送らないことで、ホットスポットを緩和できます。ただしHTTP/2の多重化が強い環境では、接続数が負荷の代理になりにくいこともあり、万能ではありません。最小接続は「偏り抑制」の手段であって、根本のボトルネック(DBや外部API)を解決するわけではない点を押さえます。
導入するなら観測とセットです。ノードごとのp95遅延、エラー率、CPU飽和、キュー長を見て、接続数が負荷の代理になっているかを検証します。代理になっていないなら、別の指標に基づくルーティングや、アプリ側の負荷制御(キュー、隔離)を検討します。方式は「入れたら終わり」ではなく「観測して調整する」運用対象です。
4.3 重み付け分散でWebサービスを段階移行する
重み付けは、段階移行(カナリア)や性能差吸収に強い方式です。新バージョンへ10%だけ流す、復旧直後は少量だけ流す、リージョン間で配分を変える、といった運用が可能になります。負荷分散はリリース戦略でもあるため、重み付けを使えると「止める条件」が設計に入りやすくなります。これは障害を避けるためだけでなく、運用に自信を持って改善を回すためにも重要です。
ただし重み付けは、LB操作がリリース操作に近づくため、設定ミスの影響が大きくなります。監査ログ、段階適用、ロールバック手順が必須です。エラー率が閾値を超えたら即0%へ戻すなど、止める条件を先に決めると、安全に運用できます。重み付けは便利な分、運用設計が前提です。
4.4 コンテンツ特性別に分散方式を使い分ける
Webサービスは静的配信、API、ストリーミング、WebSocketなど特性が混ざります。同じ方式で捌くと、特性の違いがホットスポットを生みます。たとえば長時間接続は偏りが起きやすいので最小接続やスティッキーが必要になる一方、短時間のAPIは均等配分でも良い、といった使い分けが現実的です。方式を分けることは複雑さの増加にもなりますが、特性差が大きいなら分けた方が全体の安定性は上がります。
方式選定の判断軸を短く固定すると、会議で迷いにくくなります。特に「観測可能性」と「リリース戦略との整合」は、方式の違いが運用に直結するため、後から効いてきます。
・負荷の均一性
・ノード性能差の吸収
・観測可能性
・リリース戦略との整合
5. Webサービスのヘルスチェック設計
ヘルスチェックは「生きているか」だけを見ていると事故になります。逆に重くしすぎても事故になります。負荷分散を安定させるには、ヘルスチェックを「落とす判定」と「戻す判定」の両方として設計し、部分劣化を検知し、フラップを防ぐ必要があります。ここは負荷分散が最も裏切りやすい箇所なので、意図的に設計しておく価値が大きいです。
5.1 LivenessとReadinessの分離
依存DBが一時的に遅いだけでNGにしてノードを外すと、残りノードへ集中して雪崩れます。これを防ぐにはLiveness(生存)とReadiness(受け付け可能)を分け、LBが参照すべきは基本的にReadinessにします。プロセスが生きていることと、依存が整っていることは別だからです。分離がないと「生存しているが受け付けるべきではない」状態を表現できません。
Kubernetesの例では、Readinessは「流してよいか」、Livenessは「再起動すべきか」です。アプリでも同様で、縮退可能な依存障害で全台を外さない設計が重要です。分離すると、部分劣化時に「落とさずに縮退」が可能になり、可用性と復旧の速さが上がります。
livenessProbe:
httpGet: { path: /healthz/live, port: 8080 }
readinessProbe:
httpGet: { path: /healthz/ready, port: 8080 }
5.2 依存サービス障害時の扱い
依存サービスが落ちたとき、ヘルスチェックをどう返すかは設計判断です。すべてをNGにすると全台が外れて全体が落ちますが、すべてOKにすると遅延が連鎖してタイムアウト雪崩が起きます。依存ごとに「縮退可能か」「縮退してSLOを守れるか」を決め、Readinessへ反映します。ここを曖昧にすると、障害時に人が迷い、その迷いが対応遅れとしてユーザー影響に直結します。
たとえば外部通知が落ちても本体提供は可能ならReadinessはOKのままにし、通知だけキューに積む選択があり得ます。認証DBが落ちたら提供できないのでReadinessをNGに寄せる、といった線引きです。依存障害の扱いを決めることは、負荷分散の安定性を決めることです。
5.3 Webサービス復旧判定の設計基準
落とす判定より難しいのが戻す判定です。復旧判定が緩いと、まだ不安定なノードを戻して再び落ち、フラップが起きます。フラップはトラフィック偏りとキャッシュミスを生み、全体遅延を悪化させます。復旧判定は単発成功ではなく「連続成功」「ウォームアップ完了」を条件にするのが基本です。復旧直後のノードはキャッシュも温まっておらず、依存接続も安定していないことが多いため、慎重に戻すべきです。
さらに実務では、復旧を段階的にするのが安全です。復旧直後は重みを小さくして少量だけ流し、メトリクスが安定したら増やす、という形です。復旧判定は健康かどうかだけでなく、健康を維持できるかを判定する必要があります。LBが復旧を急ぐほど、全体が不安定になるケースがある点を前提に置くべきです。
5.4 部分劣化を見抜くチェック項目
プロセスは生きているが遅い、という部分劣化が最も厄介です。CPU飽和、GCストール、スレッド枯渇、接続プール枯渇などでは、200を返せてもp95遅延が跳ねます。単なる「/healthz が200」では検知できず、遅いノードに流れ続けてSLOが壊れます。ヘルスチェックは「生存確認」ではなく「サービス提供可能性の確認」に寄せる必要があります。
部分劣化を見抜くには、軽量な内部指標を参照します。キュー長、接続プール残量、直近p95遅延、依存へのタイムアウト率など、致命的なものに絞ります。チェックが重いとそれ自体が負荷になるので、外部依存へ問い合わせるのではなく、内部メトリクスを返す軽いエンドポイントにします。チェック項目を増やしすぎると誤検知も増えるため、SLO破綻に直結する項目に集中します。
5.5 ヘルスチェック事故を防ぐ
ヘルスチェック事故の典型は、チェックが重いクエリを発行し、DBを圧迫するケースです。さらにチェックが同時に走ってスパイクを作り、NG判定が連鎖して全体が落ちることもあります。ヘルスチェックは軽く、局所で完結し、外部依存を最小化するのが原則です。特に「重い依存の確認」をヘルスチェックに含める場合は、頻度・タイムアウト・ジッターを明確に設計しないと、事故の引き金になります。
NG例とOK例を増やして比較すると、何を避けるべきかが整理しやすくなります。単に正しいチェックを作るのではなく、「チェックがサービスを落とす」状況を避けることが目的です。
| 観点 | NG例 | OK例 |
|---|---|---|
| DB依存 | 毎回重いクエリ | 軽量な接続確認+内部メトリクス |
| 復旧判定 | 1回成功で復帰 | 連続成功+ウォームアップ |
| 頻度 | 高頻度で全ノード同時 | ジッター導入+適切な間隔 |
| タイムアウト | 長く待って詰まる | 短く切って縮退に回す |
| 判定の揺れ | すぐ外す・すぐ戻す | クールダウン+段階復帰 |
6. Webサービスのセッション管理と負荷分散
セッションは負荷分散の自由度を決めます。セッションがノードに残るほどスティッキーが必要になり、偏りが生まれ、スケールと障害耐性が落ちます。逆にセッションを設計として分離できれば、LBは単純になり、オートスケールも安全になります。セッションは「便利な機能」ではなく「分散の制約条件」だと捉えると、判断が現実的になります。
6.1 スティッキーセッションが与える影響
スティッキーは短期的に実装が楽ですが、固定は偏りを生み、ホットスポットになります。ノードが落ちたときのセッション喪失も起き、復旧時にセッション由来の不具合が顕在化しやすくなります。つまりスティッキーは負荷分散の前提(均等配分)を壊すため、安易に増やすと長期で苦しくなります。特にスパイク時に偏りが増えると、LBが均等に配れないことがそのままSLO破綻に繋がります。
どうしても必要なケース(WebSocketなど)はありますが、原則は最小化です。対象パスだけに限定し、期間を短くし、可能なら後述の外部ストアへ逃がします。スティッキーを増やす前に「なぜ必要か」「どの範囲で必要か」を明文化するだけでも、偏りと事故の増殖を防げます。
6.2 Webサービスをステートレスにする設計
負荷分散に強いアプリの基本はステートレスです。どのノードへ流れても同じ結果が出る状態にすると、水平スケール、オートスケール、ローリングデプロイが安全になります。ステートレスは負荷分散の自由度を最大化する前提条件であり、LBの方式や設定より先に効く「根本設計」です。ここが整うと、ノード入れ替えや障害時の切り離しが速くなります。
ステートレス化の実務は、セッションや一時状態をプロセス内に持たないことです。ログイン状態はトークンで表現し、必要な状態は外部へ寄せます。すべてを一度にやる必要はありませんが、スケールと障害耐性を伸ばすなら、最終的に状態は外部へ出す必要があります。状態が残る限り、負荷分散は「制御できない偏り」を抱え続けます。
6.3 外部ストア活用によるセッション分離
ステートレスが難しい場合は、セッションを外部ストアへ分離します。RedisやDBでセッションを持つ設計にすると、ノード落下時にセッションが維持され、スティッキーの必要性が下がります。ただし外部ストアは新たな依存であり、そこがボトルネックや単一障害点になり得ます。セッションストアの冗長化、監視、容量設計、そして障害時の挙動(読み取りだけ許すのか、ログアウトさせるのか)まで含めて設計する必要があります。
推奨順序を固定すると判断が揃います。現場ではスティッキーが最も手軽に見えますが、長期では最も負債になりやすいので、優先順位を合意しておくのが効果的です。
・ステートレス
・外部保存(Redis等)
・スティッキー最小化
7. Webサービスのスケールアウト設計
スケールアウトは台数を増やす話に見えますが、実務では「増やしても意味がある状態」を作る話です。無状態化ができていないと、増やすほど偏りが悪化します。DBが接続数で詰まっていると、増やすほどDBが死にます。スケールアウトは、負荷分散とボトルネック設計の結節点であり、設計の順序を誤ると、スケール操作が障害を増幅します。
7.1 無状態化が前提条件
アプリが無状態であることは、スケールアウトの必須条件です。状態がノードに残ると、ノード追加で偏りが悪化し、障害時にセッションが飛び、スケールが「壊す操作」になります。無状態化は、オートスケール・フェイルオーバー・ローリングデプロイを安全にする土台です。ここを飛ばしてスケールを先に自動化すると、負荷分散は不安定さを増幅する方向に働きます。
無状態化が難しい場合でも、状態の種類を分けます。セッションは外部へ、ジョブはキューへ、キャッシュは共有へ、と段階的に逃がします。重要なのは、状態を残したまま増やすのではなく、状態の位置を外部へ寄せてから増やすことです。増やす順序を誤らなければ、スケールアウトは「守りの強化」として機能しやすくなります。
7.2 オートスケーリング指標の選び方
CPUだけでスケールすると、外部API待ちでCPUが低いのに遅延が増えるケースを見逃します。RPSだけだと、重いリクエストが増えたときに追随できません。待ち行列長やp95遅延など、飽和を示す指標を含めると、現実に近いスケールができます。指標は「増やすトリガー」なので、誤るとコストか障害が増えます。特に誤ったスケールインはフラップを生み、全体の安定性を壊します。
スケールはアウトよりインが難しいため、スケールインは慎重にしフラップを避けます。複数指標で判定し、短期ノイズで動かないようにします。スケールは自動化して終わりではなく、観測してチューニングする運用が前提です。指標は「採用した瞬間」よりも「半年後の運用」で差が出るので、変更しやすい設計(設定の外出し、閾値管理)も含めます。
| 指標 | 強み | 注意点 |
|---|---|---|
| CPU | 分かりやすい | I/O待ちを見逃す |
| RPS | トラフィック反映 | 重さの不均一 |
| 待ち行列長 | 飽和を捉えやすい | 実装が必要な場合 |
| p95遅延 | 体験に直結 | ノイズに注意 |
| メモリ使用量 | OOM前兆を捉える | GC特性で誤検知しやすい |
| エラー率 | 劣化を早く検知 | 原因切り分けが必要 |
7.3 スパイク耐性を持つWebサービス設計
スパイクはオートスケールだけでは防げません。スケールが間に合うまでの間、システムは耐える必要があります。入口でのレート制限、キューでのバッファリング、キャッシュでの吸収、機能縮退が重要です。スパイク耐性は「異常時の生存戦略」であり、平常時の最適化ではありません。ここが弱いと、オートスケールが追いつく前に雪崩れて終わります。
実務では、スパイク時に守るSLOを決め、そのSLOを守るための縮退ルールを設計に含めます。たとえば高価な機能を一時停止し、読み取りだけ優先し、外部API連携を後回しにするなどです。スパイクは必ず起きるので、起きたときの「落ち方」を決めることが負荷分散設計になります。縮退が設計されているほど、入口で遮断しすぎずにサービス価値を保ったまま生存しやすくなります。
8. WebサービスにおけるキャッシュとCDN活用
キャッシュは負荷分散の強力な一形態です。均等に配るよりも、そもそもオリジンに到達させない方が強い場面があります。入口のCDN、内部キャッシュ、整合性戦略をまとめて設計すると、スケールの伸び方が変わります。特にスパイク耐性とコスト効率に対して、キャッシュは台数増より効くことが少なくありません。
8.1 Webサービス入口で負荷を落とす設計
CDNは静的アセットだけでなく、キャッシュ可能なHTMLやAPIをエッジで捌くことでオリジン負荷を大幅に下げます。これはピーク耐性に直結し、アプリ台数を増やすよりコスト効率が良いこともあります。負荷分散は「配る」だけでなく「配らない」ことでも成立します。入口で落とせる設計があると、内部のスケールやDB分散に頼り切らない構造になります。
ただしキャッシュは鮮度と正しさの管理が必要です。TTL、バージョニング、Purge、再検証を設計しないと、古い情報を高速に配る事故が起きます。入口キャッシュを入れるほど、運用は更新の設計になります。反映遅延を許容できる領域と許容できない領域を分け、SLOとセットで取り扱うのが安全です。
8.2 内部キャッシュによる負荷吸収
内部キャッシュはDB負荷を落とし、ホットデータを高速化します。読み取りが多いサービスでは、キャッシュがボトルネックを移すほど強力です。アプリを増やすよりキャッシュヒット率を上げる方が効くケースも多く、負荷分散設計はキャッシュ戦略と不可分です。特に「読みの偏り」があるサービスほど、キャッシュの効果は大きく、LBの方式差よりも先に体感に現れます。
一方で内部キャッシュは整合性と無効化が難しく、設計が弱いと古いデータが残ります。キー設計、TTL、無効化を明文化し、事故を前提に回収できる運用(無効化手順、stale戦略、障害時の読み取り方針)を作る必要があります。キャッシュは「高速化の機能」ではなく「運用される設計」であり、運用が弱いほど事故が高頻度で起きます。
8.3 Webサービス整合性とキャッシュ戦略
整合性はデータ種別ごとに違います。決済や在庫は強整合が必要ですが、ランキングやおすすめは多少古くても許容できることがあります。キャッシュ戦略は、この鮮度許容を定義するところから始めます。許容が定義できると、TTLやstale戦略、Purgeの頻度を合理的に決められます。逆に鮮度許容が曖昧だと、TTLを短くしてヒット率が落ちる、Purge乱用でオリジンが死ぬ、といった形で破綻しがちです。
キャッシュ運用で使う操作を短く揃えると、現場の会話が安定します。これらを「どの領域に適用するか」まで含めて設計すると、キャッシュが足を引っ張りにくくなります。
・TTL(寿命)
・パージ(無効化)
・バージョニング(URL/キー変更)
・再検証(ETagなど)
9. WebサービスのDB負荷分散戦略
DBは負荷分散の最後の難所になりやすい層です。アプリやキャッシュは水平に伸ばしやすい一方、DBは整合性の制約が強く、設計が複雑になります。ここでは読み書き分離、レプリカの限界、シャーディング判断、接続数ボトルネックを整理し、DBを「増やせば解決する層」ではなく「設計で伸ばす層」として扱います。
9.1 Webサービス読み書き分離の設計思想
読みは分散しやすく、書きは分散しにくい、という性質差が出発点です。読み書き分離は「読みを広げる」「書きを守る」という思想で設計すると分かりやすくなります。負荷分散でアプリを増やしても、書きが詰まれば全体は止まるため、DBの分散は必ず考慮します。読みが多いサービスほど、読みの逃げ道を作るだけで全体の安定性が上がります。
読み書き分離では、レプリケーション遅延への対策が必要です。読み直後に書き反映が必要な画面はプライマリへ読むなど、データ種別と画面要件で線引きします。分離は性能改善のためであり、正しさを壊してはいけません。線引きが曖昧だと、アプリに例外処理が増えて複雑化し、むしろ運用が壊れます。
9.2 リードレプリカの限界
レプリカは読み負荷を分散しますが、遅延により最新が読めない瞬間が必ず発生します。負荷が高いと遅延が増え、アプリ側の例外処理が増えて複雑になります。さらに読みが増えると接続数も増え、接続管理がボトルネックになることもあります。レプリカは万能ではなく、適用範囲の線引きが成功要因です。線引きの失敗は「たまに古い」「一部だけ違う」といった再現性の低い不具合として現れやすく、対応コストが高くなります。
したがって、レプリカを増やす判断は「読みがボトルネックで、遅延許容がある」場合に限るのが安全です。遅延許容がない領域は、キャッシュや設計変更で解く必要があります。レプリカは「読みの逃げ道」ですが、逃げ道が増えるほど運用が難しくなる点も含めて判断します。逃げ道の数より、逃げ道の扱い方が運用耐性を決めます。
9.3 シャーディング導入の判断基準
シャーディングは書きの分散に踏み込む強い手段ですが、運用と設計が一段難しくなります。クエリ、トランザクション、集計、障害対応が難しくなるため、まずはクエリ最適化、インデックス、接続プール、キャッシュ、テーブル/DB分割で延命し、それでも書きが限界なら検討します。シャーディングは「性能」ではなく「運用能力」が前提になる設計で、運用筋力が不足していると平常時の複雑さだけが増えます。
判断基準は、分割キーが自然に存在するか(ユーザーID等)、集計要件が許容できるか、将来の書き増加が不可避かです。キーが曖昧なまま始めると、後で結合や集計で詰みます。シャーディングは導入前に成功条件を明確にし、導入後に「戻せる」設計(段階導入、カナリア、二重書き期間の扱い)まで含めて考えるのが実務的です。
9.4 Webサービス接続数ボトルネックとプール設計
DBはCPUより先に接続数で詰まることが多いです。アプリをスケールアウトすると接続が増え、DBが接続上限に達して落ちます。これは「負荷分散が成功したから起きる事故」であり、接続プール設計がないと必ず踏みます。アプリの台数とDB接続管理はセットで設計し、スケール操作がDBを殺さないようにします。
実務では、プール上限、アイドル管理、タイムアウト、必要なら接続プロキシを検討します。接続数を観測し、スケール操作に連動させる必要があります。さらに、論理的な分割(テーブル分割、機能別DB分離、パーティショニング)を組み合わせると、シャーディングより手前で伸びる場合もあります。接続問題は「DBが遅い」のではなく「接続が過剰」という形で現れるので、最初から観測項目に含めるのが安全です。
| 対策 | 期待効果 | 注意点 |
|---|---|---|
| 接続プール | 接続数を制御 | 設定ミスで枯渇 |
| クエリ最適化 | DB負荷低減 | 効果が局所に偏る |
| 読み書き分離 | 読みの分散 | 遅延と整合性 |
| 分割設計 | 書きの分散 | 運用が難化 |
| パーティショニング | 局所性向上・運用軽め | キー設計が重要 |
| バッチ化/集約 | 書き負荷平準化 | 遅延許容の合意が必要 |
10. Webサービス障害設計とフェイルオーバー
負荷分散は平常時の性能だけでなく、障害時の継続性を決めます。単一障害点を排除し、マルチAZ/リージョンを選び、フェイルオーバーとロールバックを設計に含めることで、SLOを守れる確率が上がります。ここは「落ちない設計」を現実の手順と責務に落とす章であり、技術よりも運用の筋力が結果を左右します。
10.1 Webサービスの単一障害点を排除する
LBが1台ならLBが落ちたら終わり、DBが単一ならDBが落ちたら終わりです。入口、アプリ、キャッシュ、DB、DNS、証明書管理など、どこが単一障害点かを列挙し、どの障害を許容し、どの障害を許容しないかを決めます。すべてを冗長化するとコストと運用が爆発するため、SLOに合わせて投資します。ここで重要なのは、可用性を上げたい一心で複雑さを上げ、結果として運用不能になる失敗を避けることです。
SPOF排除は冗長化だけでなく「切り離し」でも実現できます。外部APIが落ちても本体を動かすために隔離する、ログ基盤が落ちてもサービス提供は続ける、などです。依存関係の設計はそのまま障害耐性の設計になります。依存が多いサービスほど、全部を守るのではなく、守るものをSLOで決めて守る方が強いです。
10.2 マルチAZ・マルチリージョン設計
マルチAZは現実的な基本で、データセンタ単位の障害に耐えます。アプリを複数AZへ分散し、LBも冗長化し、DBもAZを跨いで冗長化します。マルチリージョンはリージョン障害に備えますが、データ整合性・遅延・運用が一段難しくなります。必要条件が揃わないのにマルチリージョンへ行くと、平常時の複雑性だけが増えます。つまり「最悪に備える」設計ほど、日常の運用能力が前提になります。
設計判断は、SLOとビジネス影響から逆算します。リージョン障害が許容できない業務なら必要ですが、許容できるならマルチAZ+復旧手順で十分な場合もあります。フェイルオーバーは自動化できるかも重要で、できないなら訓練と手順も設計の一部です。「自動化できないものは設計できない」ではなく「自動化できないなら訓練まで含めて設計する」が現実解です。
10.3 フェイルオーバーとロールバック戦略
フェイルオーバーは成功しても、復旧後に「戻す」設計が必要です。切り替えたら終わりではなく、元に戻すか、新しい正本をどう決めるかが問題になります。データが絡むほど難しくなるため、フェイルオーバーはデータ設計と一体です。また、切替中にリリースが混ざるとロールバックが難しくなるので、リリース戦略との整合も必要です。フェイルオーバー手順は「実行できる」だけでなく「迷わず実行できる」状態が重要です。
チェックリストとして短く持つと運用が揃います。ここを文章で合意し、訓練で確認し、改善サイクルを回すことで、負荷分散は“構成の正しさ”から“運用の強さ”へ移ります。
・単一障害点の洗い出し
・切替の自動化可否と手順
・切替後の復旧と戻し方
・データ整合性の扱い
・切替中のリリース制御
11. Webサービス負荷分散の監視と可視化
負荷分散は「入れたら終わり」ではなく、「観測して制御する」仕組みです。観測が弱いと、ボトルネックを誤り、偏りを見逃し、誤検知で疲弊します。ここでは入口指標から偏り検知、トレーシング、誤検知対策までを整理し、運用で負荷分散を「使える道具」にします。観測はコストですが、観測がない運用は賭けになり、賭けは長期では必ず負けます。
11.1 Webサービス入口指標の設計
入口指標(RPS、p95/p99遅延、4xx/5xx、タイムアウト率)はユーザー影響に直結します。入口で異常を検知できれば、内部の切り分けが速くなり、縮退や遮断で被害を止めやすくなります。入口監視はSLOの実体であり、最優先の観測点です。ここが弱いと、内部の改善をしても「ユーザーがどう感じたか」を測れず、最適化が自己満足になりやすくなります。
ただし入口指標だけでは原因が分かりません。入口異常から内部の疑い箇所へ繋げる「観測の地図」が必要です。入口が遅いときに、DBなのか、外部APIなのか、キューなのか、ノード偏りなのかを、指標の組み合わせで絞り込めるようにします。観測は「多いほど良い」ではなく「意思決定が速くなる形」が良いです。
11.2 ノード偏り検知とホットスポット対策
負荷分散が入っていても、ノード偏りは必ず起きます。原因はスティッキー、コネクション再利用、特定パスの重さ、キャッシュ差、GCの揺れなどです。偏りを放置すると、遅いノードがさらに遅くなり、LBが外して残りが死ぬ、という雪崩が起きます。したがって、ノードごとのp95遅延、エラー率、CPU、キュー長を監視し、偏りを検知します。偏りは「起きたら直す」ではなく「起きる前提で緩和する」ことが重要です。
対策は方式選定だけではありません。復旧直後のノードへ徐々に流す、キャッシュウォームアップをする、重いパスを別ターゲットへ分離する、といった運用設計も効きます。偏りは「方式を変えたら終わり」ではなく「観測と運用で抑える」対象です。偏りの検知と緩和が整うほど、負荷分散は安定します。
11.3 分散環境におけるトレーシング設計
負荷分散が入ると、1リクエストが複数サービスを跨ぎ、原因追跡が難しくなります。入口で遅いと分かっても、どの層で遅いかが分からないと対策が打てません。分散トレーシングは、遅延の原因の地図を作るための必須要素で、オートスケールや障害設計の精度にも直結します。特に外部API待ちやDB待ちなど、待ち時間が連鎖する系の障害では、トレーシングがないと推測で対応することになります。
トレーシングはサンプリング、PII、コスト、タグ設計が必要で、全部取るとコストが爆発します。SLOに直結するパスを優先し、異常時にサンプリングを増やすなどの運用が現実的です。観測は「データを集める」ことではなく「意思決定を速くする」ことなので、取るべき情報を絞り、取った情報を使える形にする設計が重要です。
11.4 誤検知と向き合う
監視が増えると誤検知が増え、誤検知が多いとアラートが無視されます。逆にアラートを絞りすぎると兆候を見逃します。誤検知はなくすのではなく「扱える量にする」設計が必要です。SLO直結アラートと調査用アラートを分け、行動が揃うようにします。ここでのポイントは、アラートが鳴った瞬間に「次に何を確認するか」が決まっていることです。
観測項目→異常兆候→疑う箇所を表に落としておくと、誤検知でも行動が揃います。さらに「キュー長」や「キャッシュヒット率」のような指標を加えると、ボトルネックの絞り込みが速くなり、無駄な調査を減らせます。
| 観測項目 | 異常兆候 | 疑う箇所 |
|---|---|---|
| p95遅延 | 継続的上昇 | DB/外部API/キュー飽和 |
| 5xx率 | 急増 | アプリ障害/依存障害 |
| ノード偏り | 一部だけ高負荷 | スティッキー/キャッシュ差 |
| 接続数 | 上限付近 | DBプール/プロキシ |
| キュー長 | 急増・戻らない | 非同期処理詰まり/リトライ暴走 |
| キャッシュヒット率 | 低下が継続 | 無効化乱用/キー設計/ホットデータ変化 |
12. Webサービス負荷分散設計の段階的導入手順
負荷分散は高度化するほど複雑になります。最初から完璧を目指すと、運用が追いつかず事故が増えます。したがって段階的に、最小構成→安定化→拡張の順で進めるのが現実的です。ここでは、増やす順序を間違えないための導入手順を整理し「高度化したのに不安定になった」という失敗を避けます。
12.1 最小構成から始めるWebサービス分散
最小構成は、入口LB+アプリ冗長+基本監視から始めます。ここでの目的は「壊れ方を観測できる状態」を作ることです。無理に高度なルーティングやマルチリージョンへ行くと、原因切り分けが難しくなり、改善速度が落ちます。まずはSLOを仮置きし、ヘルスチェックを健全化し、最低限の冗長性を確保します。最小構成の段階で「落ち方」を把握できるほど、後の高度化が安全になります。
最小構成で重要なのは、ヘルスチェックと観測です。ここが弱いと、最小構成でも雪崩れます。逆にここが強いと、後からキャッシュ、DB分離、オートスケールを足しても破綻しにくくなります。土台が整うほど高度化は足し算になります。最小構成は「小さく作る」のではなく「小さく運用できる」ことが目標です。
12.2 安定化フェーズで整える項目
安定化フェーズでは、観測と制御点を増やします。入口指標と内部指標の整合、ノード偏り検知、スケール指標の検証、依存障害時の縮退ルール、接続プール設計などです。このフェーズでやるのは「壊れ方を制御する工夫」であり、性能最適化より優先されます。壊れ方が制御できるほど、スケールアウトは安全になり、障害対応も定型化できます。
運用面では、重み付けやカナリア、ロールバック手順、アラート設計の見直しを行います。負荷分散は運用とセットなので、安定化は技術と運用を同時に強くするフェーズです。ここを飛ばして拡張すると、複雑さだけが増えます。安定化は地味ですが、最終的に最もROIが高い投資になりやすいです。
12.3 拡張フェーズにおけるWebサービス高度化
拡張フェーズでは、ボトルネックに応じて投資先を選びます。入口が詰まるならCDN、アプリが詰まるなら非同期化、DBが詰まるなら読み書き分離や分割、リージョン障害が許容できないならマルチリージョン、といった具合です。重要なのは、先に観測があり、どこがボトルネックかが分かっていることです。分かっていれば高度化は局所投資になり、破綻しにくくなります。逆に観測がない高度化は、改善ではなく賭けになります。
高度化が進むほど、止める条件(どの指標が悪化したら戻すか)を設計に含めます。段階導入、ロールバック、訓練を前提に進めると、複雑さを増やしすぎずに進化できます。負荷分散設計が成熟するとは、豪華な構成になることではなく「段階的に変えられる」ことです。変えられる設計は、成長速度が上がるほど価値が増えます。
まとめ
負荷分散の本質は「均等配分」ではなく「局所化と継続」です。SLOを短く固定し、どの障害を許容し、守れないときはどう縮退するかを先に決めると、LB方式の選定もヘルスチェック設計も迷いにくくなります。特にReadinessと復旧判定、段階復帰、依存障害時の扱いは、構成の豪華さよりも運用の安定性に直結します。
全体設計では、入口だけを強化しても内部のボトルネックが残れば成果は出ません。セッションが残れば分散の自由度は下がり、接続数が詰まればスケールアウトが事故になります。キャッシュとCDNは「配る」以前に「到達させない」手段として強力で、DBは最後の難所として読み書き分離や分割判断、接続プール設計が避けて通れません。どの層を伸ばすべきかは、観測できて初めて判断できます。
導入は最小構成から始め、安定化で観測と制御点を揃え、拡張はボトルネックに狙い撃ちで足すのが現実的です。重み付けやカナリア、ロールバック、訓練まで含めて「変えられる設計」にしておくと、成長局面でも改善が止まりにくくなります。負荷分散は完成形を作る仕事ではなく、変化の中でも安全に更新できる状態を維持する仕事だと捉えると、長期で強い設計になります。
EN
JP
KR