システムデザイン入門

大規模システムを設計するためのロードバランサ、キャッシング、データベースのスケーリング、CAP定理などを図解で体系的に学びます。

学習をスタートする

ロードマップ

1

システムデザインの基礎とスケーラビリティ

Web アプリケーションやシステムが成長し、アクセス数が増加するにつれて、「いかにしてシステムをダウンさせず、高速に応答し続けるか」が極めて重要になります。 第1章では、システム設計(システムデザイン)の基礎概念であるスケーリング手法、ロードバランサによる負荷分散、および高可用性を実現する冗長化の仕組みについて学びます。 1. 垂直スケーリング vs 水平スケーリング システムにかかる負荷を処理するために、サーバーのキャパシティを増やす方法は大きく分けて2つあります。 比較項目 垂直スケーリング (スケールアップ) 水平スケーリング (スケールアウト) アプローチ 単一サーバーのCPU、メモリ、SSDなどのスペックを強化する。 サーバーの数を増やし、処理を分散させる。 主なメリット 構成が単純。アプリケーションの修正が不要。 理論上、無限にスケールできる。コスト効率が高い。 主なデメリット ハードウェアの物理限界がある。スペック増強に伴うコスト増加が非線形。 システムが複雑になる。セッションやデータの共有設計が必要。 適した用途 データベースサーバーの初期段階、構成変更を最小限にしたい場合。 大規模Webサイト、マイクロサービス、Webアプリケーション層。 2. ロードバランサによる負荷分散 水平スケーリングを行う場合、クライアントからのリクエストを複数のサーバーに適切に振り分ける 「ロードバランサ(Load Balancer: 負荷分散装置)」 が不可欠になります。 L4 ロードバランサ vs L7 ロードバランサ ロードバランサは、動作する OSI 参照モデルのレイヤーによって分類されます。 1. L4 ロードバランサ (レイヤー4 - トランスポート層) * 特徴: IPアドレスやポート番号(TCP/UDP)の情報に基づいてルーティングします。 * 利点: パケットの中身(HTTPヘッダーやデータ部)をパースしないため、極めて高速に処理できます。 2. L7 ロードバランサ (レイヤー7 - アプリケーション層) * 特徴: HTTP/HTTPS ヘッダー、クッキー、URL パス、リクエストボディなどの情報に基づいてルーティングします。 利点: /api/ は API サーバーへ、/static/* は静的配信サーバーへといった柔軟な条件分岐(コンテンツベースのルーティング)や、SSL終端(SSL復号化)が可能です。 主要なルーティングアルゴリズム * ラウンドロビン (Round Robin): サーバーリストの順番通りに均等に割り振る。サーバーのスペックが均一な場合に適する。 * 重み付きラウンドロビン (Weighted Round Robin): サーバーの処理能力に応じて「重み(比重)」を設定し、スペックの高いサーバーにより多くのリクエストを割り振る。 * 最小接続 (Least Connections): 現在アクティブな接続数が最も少ないサーバーに優先して割り振る。処理時間の長いリクエストが多い場合に有効。 * IPハッシュ (IP Hash): クライアントのIPアドレスからハッシュ値を計算し、転送先サーバーを固定する。セッションを特定のサーバーで保持したい場合(ステートフル)に使用。 3. 高可用性(High Availability)と単一障害点(SPOF) システムデザインにおいて最も避けるべきなのが、SPOF(Single Point of Failure: 単一障害点) です。SPOF とは、そこが停止するとシステム全体が停止してしまうようなコンポーネントを指します。 可用性(SLA)の算出方法 稼働率(システムが正常に稼働している時間割合)を計算する際、コンポーネントの接続方式によってシステム全体の稼働率は大きく変化します。 1. 直列接続(コンポーネントがすべて正常である必要がある場合) データベースとアプリケーションサーバーのように、両方が動いていなければならない構成です。 $$稼働率 = 稼働率A \times 稼働率B$$ [!NOTE] 例:稼働率 $99\%$ のコンポーネントが2つ直列に繋がると、全体の稼働率は $99\% \times 99\% = 98.01\%$ に低下します。 2. 並列接続(どちらか一方が動いていれば良い場合:冗長化) ロードバランサ配下の複数のサーバーのように、片方が壊れてもサービスが継続できる構成です。 $$稼働率 = 1 - (1 - 稼働率A) \times (1 - 稼働率B)$$ [!NOTE] 例:稼働率 $99\%$ のサーバーを2台並列化すると、全体の稼働率は $1 - (0.01 \times 0.01) = 99.99\%$ に向上します。 アプリケーションのステートレス化 水平スケーリングと高可用性を達成するためには、Web サーバーを 「ステートレス(状態を持たない)」 に設計することが極めて重要です。 セッション情報やアップロードされたファイルをサーバーのローカルメモリやローカルディスクに保存するのではなく、外部の Redis(分散セッションキャッシュ)や S3(オブジェクトストレージ)に集約することで、どのサーバーが停止してもユーザーは他のサーバーで継続して処理を受けることができます。 まとめ * 水平スケーリングはサーバー台数を増やすアプローチで、大規模システム設計の基本である。 * ロードバランサはL4とL7の使い分けがあり、用途に応じて適切なルーティングアルゴリズムを選択する。 * SPOF を排除するためには、並列冗長化を導入し、アプリケーションサーバーをステートレスにする必要がある。

2

キャッシュ戦略とコンテンツ配信

応答速度を向上させ、データベースやバックエンドサーバーの負荷を劇的に下げるための最も強力な手法の一つが 「キャッシング(Caching)」 です。また、地理的に近い場所から静的ファイルを届ける 「CDN(コンテンツ配信ネットワーク)」 もモダンなWebシステムには欠かせません。 第2章では、キャッシュの様々なパターン、データの整合性を維持するための戦略、および CDN のアーキテクチャについて学びます。 1. キャッシュの階層と分類 キャッシュとは、時間のかかる計算や遠くのデータベースから取得したデータを、一時的に高速に読み書きできるメモリ領域に保存しておく仕組みです。 キャッシュの配置場所 1. クライアントキャッシュ (ブラウザキャッシュ) * HTTP ヘッダー (Cache-Control) を利用し、画像や JS/CSS などのアセットをブラウザ内に保存します。 2. CDN / エッジキャッシュ * 世界各地に分散配置されたプロキシサーバーで静的・動的ファイルをキャッシュし、オリジンサーバーの手前でリクエストを処理します。 3. アプリケーションキャッシュ (ローカルメモリ) * Web サーバーのプロセス内メモリ(Node.js のオブジェクトメモリなど)にデータを一時保存します。高速ですが、サーバー間でデータが同期されないデメリットがあります。 4. 分散キャッシュ (Redis / Memcached) * アプリケーションサーバーの外部に、メモリ型の専用データベースを構築します。複数のサーバー間で同一のキャッシュデータを安全に共有できます。 2. 代表的なキャッシュパターン(読み書き戦略) データを読み書きする際、アプリケーション、キャッシュ、データベースの間でどのようなフローをとるべきかはシステム要件によって決まります。 ① Cache-Aside(キャッシューアサイド)/ Lazy Loading 最も一般的で、実装が容易な読み取り戦略です。 * メリット: キャッシュサーバーが一時的にダウンしても、DB に直接アクセスするためシステム全体は停止しない(障害耐性)。 * デメリット: キャッシュミスが発生した最初のアクセスが遅くなる。また、DB の直接更新によるデータの不整合が発生しやすい。 ② Write-Through(ライトスルー) 書き込み時、常にキャッシュとデータベースの両方に同時に書き込みます。 * フロー: アプリ $\rightarrow$ キャッシュに書き込み $\rightarrow$ キャッシュが即座に DB に書き込み $\rightarrow$ 完了をアプリに通知。 * 特徴: キャッシュが常に最新に保たれ、読み取りが常に高速になりますが、書き込みの遅延(レイテンシ)は増加します。 ③ Write-Behind(ライトビハインド)/ Write-Back データをまずキャッシュにだけ書き込み、後から非同期でまとめてデータベースに書き込みます。 * フロー: アプリ $\rightarrow$ キャッシュに書き込み $\rightarrow$ 即座に完了通知 $\rightarrow$ バックグラウンドで非同期に DB に一括書き込み。 * 特徴: 書き込みパフォーマンスが極めて高くなりますが、DB に反映される前にキャッシュサーバーがクラッシュすると、書き込みデータが消失するリスクがあります。 3. キャッシュ無効化と破棄ポリシー(Eviction) キャッシュサーバーのメモリは有限です。容量がいっぱいになったとき、どのデータを破棄してメモリスペースを空けるかを決めるのが 「Eviction Policy(破棄ポリシー)」 です。 * LRU (Least Recently Used) * 最も長い時間「参照されていなかった」古いデータを優先的に破棄します。キャッシュの実装で最も広く採用されています。 * LFU (Least Frequently Used) * 「参照された回数」が最も少ないデータを優先的に破棄します。頻繁にアクセスされるホットキーを守るのに適しています。 * FIFO (First-In, First-Out) * 参照回数に関係なく、「最初にキャッシュに入った」データを順番に破棄します。 また、データが古くなったまま残り続けるのを防ぐため、必ず TTL(Time To Live: 生存時間) を設定し、自動的に期限切れになるように設計するのが鉄則です。 4. CDN (Content Delivery Network) の仕組み CDN は、インターネット上に分散配置されたサーバー群で構成され、静的コンテンツ(画像、動画、CSS、JS)をクライアントの物理的な位置に近い「エッジサーバー(PoP)」から配信します。 CDN 導入のメリット * 応答時間の短縮: クライアントからミリ秒単位の物理的距離でデータを配信できるため、ページの表示速度が大幅に向上します。 * オリジン負荷の大幅な削減: リクエストの 90% 以上がエッジでキャッシュヒット(キャッシュオフロード)すれば、本番サーバーのスペックを抑えられます。 * DDoS攻撃対策: 大量のトラフィックをエッジネットワーク全体で吸収・緩和させることが可能です。 まとめ * キャッシュは Cache-Aside のような読み取りパターンや、データの整合性を担保する書き込み戦略(Write-Through / Write-Behind)をユースケースに応じて選定する。 * メモリリークを防ぐため、LRU などの破棄ポリシーと適切な TTL の設定が必須。 * CDN は物理的距離の遅延を解消し、オリジンの帯域や負荷を保護するための基盤技術である。

3

データベースのスケーリングとCAP定理

アプリケーションサーバーはステートレスに設計することで簡単に水平スケーリングできますが、データを保持する 「データベース(Database)」 は状態を持つ(ステートフルである)ため、スケーリングが最も困難なコンポーネントです。 第3章では、データベースの書き込みと読み込みをスケールさせる手法、および分散データストアを設計する上での物理限界を示す「CAP定理」について学びます。 1. 読み込みのスケーリング:レプリケーション 多くの Web アプリケーションでは、書き込み(Write)よりも読み取り(Read)の割合が圧倒的に多くなります。読み取りの負荷を分散させる一般的な手法が 「レプリケーション(Replication: 複製)」 です。 プライマリ/レプリカ構成(Master/Slave) * プライマリ(主)データベース: すべての更新処理(INSERT / UPDATE / DELETE)を受け付けます。 * レプリカ(従)データベース: プライマリから複製されたデータを保持し、読み取り(SELECT)処理のみを実行します。 レプリカラグと整合性モデル プライマリからレプリカへのデータ同期は、パフォーマンス向上のため通常 非同期 で行われます。このため、プライマリに書き込まれてからレプリカに反映されるまでにタイムラグ(レプリカラグ)が生じます。 * 強い整合性 (Strong Consistency): 書き込みが完了した直後に、どのノードから読み込んでも必ず最新のデータが取得できる。同期レプリケーションが必要となり遅延が増加する。 * 最終整合性 (Eventual Consistency): 一時的にデータが古くなる可能性があるが、十分な時間が経過すれば、最終的にすべてのレプリカが同一データに同期する。非同期レプリケーションで得られる標準的な整合性モデル。 2. 書き込みのスケーリング:シャーディング 読み取り負荷はレプリカを増やすことで対応できますが、書き込み負荷がプライマリデータベースの処理限界を超えた場合は、データを複数の独立したデータベースに分割して保存する 「シャーディング(Sharding: 水平分割)」 が必要です。 シャーディングのデータ分割方式 シャード間でデータをどのように分配するかを決めるのが 「シャードキー(Shard Key)」 です。 1. レンジベース (範囲検索ベース) * 特定のID範囲(例:ユーザーID 1〜10000はシャードA、10001〜20000はシャードB)で分割します。実装は容易ですが、特定のシャードにデータが偏る(ホットスポット)問題が起きやすいです。 2. ハッシュベース (剰余演算等) * Hash(UserId) % シャード数 のように、ハッシュ値を利用して均等にデータを分散させます。データは偏りにくいですが、シャードを後から追加する際のリバランス(データの再配置)が極めて複雑になります。 3. CAP定理の理解とデータストアの選定 分散データベースシステムを設計する上で、物理的なトレードオフの関係を示した有名な定理が 「CAP定理」 です。 分散システムにおいては、以下の3つの特性のうち、同時に2つしか満たすことができないとされています。 * Consistency (整合性): すべてのクライアントがどのノードにアクセスしても、同一の最新データを読み取れる。 * Availability (可用性): ノードが一部ダウンしていても、動作しているノードは必ず応答を返せる(エラーやタイムアウトを返さない)。 * Partition Tolerance (分断耐性): ノード間の通信ネットワークが寸断(パーティション)されても、システムが動作し続けられる。 実際、ネットワークは物理的に必ず障害が起こる(寸断される)可能性があるため、現実の分散システム設計においては 「P (分断耐性) は必須」 となり、「C(整合性)を取るか、A(可用性)を取るか」 の二者択一を迫られます。 システムタイプ 特徴と障害時の挙動 代表的な技術 CP システム (整合性 + 分断耐性) ネットワーク分断時、データの一貫性を守るために、同期できないノードへの書き込み/読み込みを拒否(エラーを返す)する。 PostgreSQL (強同期構成), MongoDB, Redis, HBase AP システム (可用性 + 分断耐性) ネットワーク分断時でも、各ノードは手元の古いかもしれないデータをそのまま返し、稼働し続ける。分断復旧後にデータをマージする。 Cassandra, DynamoDB, CouchDB まとめ * データベースの読み込み負荷は レプリケーション(プライマリ/レプリカ)によってスケールさせ、最終整合性モデルを受け入れることでスケーラビリティを最大化する。 * データベースの書き込み負荷が限界に達した場合は シャーディング(水平分割)を行うが、データ移行やジョインの難易度が大きく向上する。 * 分散データ設計の際は CAP定理 に則り、システムが「C(整合性)」と「A(可用性)」のどちらを重視すべきか、ビジネス要件に基づいて冷静に判断する。

4

ロードバランサとリバースプロキシ

大規模なWebアプリケーションを安定して運用するためには、サーバー単体の性能向上だけでなく、サーバーの前面に配置する仲介サーバーの設計が重要になります。 第4章では、リクエストを受け取る窓口となる 「ロードバランサ(Load Balancer)」 と 「リバースプロキシ(Reverse Proxy)」 の違い、およびリバースプロキシが果たす多様な役割について学びます。 1. ロードバランサ vs リバースプロキシ どちらもクライアントとサーバーの間に位置してトラフィックを制御しますが、その「主たる目的」に違いがあります。 比較項目 ロードバランサ(LB) リバースプロキシ(RP) 主な目的 トラフィックを複数のバックエンドサーバーに分散し、可用性とスケーラビリティを向上させる。 クライアントからのリクエストを仲介し、セキュリティ、キャッシュ、SSL処理などの付加価値を提供する。 分散対象 通常、同一機能を持つ複数のサーバー群。 単一のサーバーの場合もあれば、異なる機能を持つ複数のサーバー(API、静的配信など)の場合もある。 代表的な位置づけ システムの最前面(DNSの直後など)に配置され、複数のリバースプロキシやWebサーバーへ振り分ける。 Webサーバー(Appサーバー)の直前に配置され、細かなリクエスト制御や前処理を行う。 [!NOTE] 現代のコンポーネント(例: Nginx, AWS ALB)は、リバースプロキシでありながらロードバランサの機能も兼ね備えている ことが多いため、境界線は曖昧になりつつあります。しかし、設計コンセプトとしての役割の違いを理解することは非常に重要です。 2. リバースプロキシとは?(フォワードプロキシとの違い) プロキシ(代理)には、「フォワードプロキシ」と「リバースプロキシ」の2種類が存在します。 フォワードプロキシ (Forward Proxy) * 役割: クライアント側を代理します。社内ネットワークなどからインターネットへアクセスする際、クライアントの身元(IPアドレス)を隠したり、危険なサイトへのアクセスをフィルタリングしたりします。 リバースプロキシ (Reverse Proxy) * 役割: サーバー側を代理します。インターネットからのアクセスを代表して受け取り、適切なバックエンドサーバーへリクエストを転送します。クライアント側はバックエンドサーバーの存在を意識しません。 3. リバースプロキシの重要な役割 単にリクエストを右から左へ流すだけでなく、リバースプロキシはWebシステムのパフォーマンスやセキュリティを高めるために以下の重要な役割を担います。 ① セキュリティと隠蔽 バックエンドのアプリケーションサーバー(Node.js, Go, Pythonなど)をインターネットに直接公開すると、OSやランタイムの脆弱性を突かれるリスクが高まります。リバースプロキシを前面に置くことで、バックエンドサーバーの実際のIPアドレスを隠蔽し、直接の攻撃を防ぐ壁として機能させます。 ② SSL/TLS終端 (SSL Termination) HTTPS通信の暗号化・復号処理(SSLハンドシェイクなど)は、CPU負荷の高い処理です。 リバースプロキシでSSL/TLSを復号(終端)し、リバースプロキシとバックエンドサーバー間は高速なHTTP(暗号化なし、または簡易暗号化)で通信することで、アプリケーションサーバーのCPUリソースをビジネスロジックの実行に集中させることができます。 ③ 静的コンテンツの高速配信とキャッシュ HTML, CSS, JavaScript, 画像などの静的ファイルは、アプリケーションサーバー(Node.jsなど)で処理するよりも、C言語等で極限まで最適化されたリバースプロキシ(Nginxなど)から直接ディスク読み出し・キャッシュ配信するほうが圧倒的に高速かつ低リソースで処理できます。 ④ バッファリングと圧縮 * バッファリング: 遅い回線のクライアントからの接続をリバースプロキシが肩代わりし、レスポンスデータを一時的にバッファ(メモリ/ディスク)に溜めてからクライアントに少しずつ送ります。これにより、バックエンドサーバーは瞬時に処理を完了して次のリクエストに備えられます。 * 圧縮: クライアントにデータを返却する前に、Gzip や Brotli アルゴリズムを用いてデータを圧縮し、ネットワーク帯域を節約します。 まとめ * ロードバランサは「負荷の均等分散」、リバースプロキシは「セキュリティ向上、SSL終端、静的ファイル配信などの前処理・最適化」が主目的である。 * SSL終端によって、重い暗号化処理をプロキシに集約し、バックエンドのCPU負荷を大幅に削減できる。 * Nginx などのリバースプロキシは、静的ファイルの高速配信やレスポンスバッファリングを行い、システム全体の応答性能を高めている。

5

メッセージキューとPub/Sub

システムが大きくなり、多くのマイクロサービスやバックエンド処理が連携するようになると、サービス間の通信方法が全体のパフォーマンスと信頼性を左右するようになります。 第5章では、システムを疎結合にし、急激なアクセス(スパイク)からデータベースを守るための 「非同期メッセージング(メッセージキューとPub/Sub)」 の仕組みとメリットについて学びます。 1. 同期通信 vs 非同期通信 システム間の連携方法は、大きく「同期通信」と「非同期通信」に分類されます。 同期通信 (Synchronous) クライアントがリクエストを送信した後、サーバーが処理を完了してレスポンスを返すまで 待機(ブロック) する通信方式です(例: HTTP REST API, gRPC)。 * メリット: 結果が即座にわかるため、実装やデータの整合性管理がシンプル。 * デメリット: 呼び出し先のサービスがダウンしていると、呼び出し元もエラーになる(障害の連鎖)。呼び出し先が遅いと全体の応答速度が低下する。 非同期通信 (Asynchronous) リクエスト(メッセージ)をメッセージブローカーに預け、受信完了の通知を受け取ったら、実際の処理の完了を 待たずに次の処理へ進む 方式です。 * メリット: 呼び出し先が一時停止していてもシステム全体が止まらない。時間のかかる重い処理をバックグラウンドに回せる。 * デメリット: 結果が即座に確定しないため、「最終的な整合性(Eventual Consistency)」を意識した設計が必要。 2. メッセージキュー (Message Queue) の仕組み メッセージキューは、「Point-to-Point(1対1)」 の通信パターンを採用した非同期通信の仕組みです。 * プロデューサー (Producer): 処理要求(メッセージ)を作成し、キューに送信する側。 * キュー (Queue): メッセージを一時的に保持するバッファ。コンシューマーが受け取るまでメッセージを保持し続けます。 * コンシューマー (Consumer): キューからメッセージを取り出して処理を実行する側。 * 特徴: ひとつのメッセージは、必ずひとつのコンシューマーによってのみ処理されます。 コンシューマーの数を増やす(水平スケールする)ことで、キューに溜まったメッセージを並列で高速に消化できます(競合コンシューマーパターン)。 * 代表例: AWS SQS, RabbitMQ 3. Pub/Sub (パブリッシュ/サブスクライブ) の仕組み Pub/Subは、「1対多(ブロードキャスト)」 の通信パターンを採用したイベント駆動型のメッセージングです。 * パブリッシャー (Publisher): メッセージを特定の受信者を意識せず、トピック(Topic) と呼ばれるチャンネルに対して発行(Publish)します。 * サブスクライバー (Subscriber): 興味のあるトピックを購読(Subscribe)しておき、トピックにメッセージが流れると自動的にそれを受け取って処理します。 * 特徴: 同一のメッセージが、そのトピックを購読しているすべてのサブスクライバーに送信されます。 送信側と受信側はお互いの存在を全く知らないため、極めて疎結合になります。 * 代表例: Apache Kafka, AWS SNS, Google Cloud Pub/Sub, AWS EventBridge 4. メッセージング導入の3大メリット ① スパイク対策と負荷平滑化(バッファリング) ECサイトのセール開始直後など、短時間に大量のアクセスが集中(スパイク)した際、リクエストのたびに重い処理(PDF領収書生成など)やデータベース書き込みを直接行うと、接続数が限界に達してサーバーがクラッシュします。 リクエストを一旦キューに保存することで、バックエンドのコンシューマーは自身が処理可能なスピード(マイペース)で順次メッセージを消化でき、システム全体のクラッシュを防ぐことができます。 ② システムの疎結合化(デカップリング) 例えば「ユーザー登録」が行われた際、「メール送信」「ポイント付与」「外部CRMへの同期」という処理が必要だとします。 これらを同期通信で連鎖させると、どれか1つが失敗しただけでユーザー登録全体がエラーになります。 Pub/Subを導入し、「ユーザーが登録された」というイベントをトピックに投げるだけにすれば、各処理は独立して実行され、後から「LINE通知機能」などを追加する際もユーザー登録処理本体のコードを修正する必要がありません。 ③ 耐障害性の向上(メッセージの永続化) バックエンドサーバー(コンシューマー)にバグが発生し、一時的に停止してしまった場合でも、メッセージキューにメッセージが安全に保持されます。バグを修正してコンシューマーを再起動すれば、停止していた時間帯のメッセージから再開し、データを1件も損失することなく処理を再完了させることができます。 まとめ * 同期通信は呼び出し先の完了を待つが、非同期通信はメッセージブローカーにリクエストを預けて即座に次に進む。 * メッセージキュー(Point-to-Point) は1つのメッセージを1つのコンシューマーが処理する(負荷分散向き)。 * Pub/Sub は1つのメッセージを複数の異なるサブスクライバーへ配信する(イベント駆動・マイクロサービス連携向き)。 * 非同期通信によって、システムの疎結合化(デカップリング)、スパイク時の負荷平滑化(バッファリング)、耐障害性の向上が実現できる。

6

APIゲートウェイとBFFパターン

マイクロサービスアーキテクチャの進展に伴い、クライアントと各バックエンドサービス間の通信をどのように整理するかが非常に重要になってきました。 第6章では、複数のマイクロサービスへのアクセスを統合する 「APIゲートウェイ」 と、特定のフロントエンド向けにAPIを最適化する 「BFF(Backend For Frontend)」 について学びます。 1. APIゲートウェイとは? APIゲートウェイは、システム外部のクライアントからのリクエストをすべて受け取り、適切なバックエンドのマイクロサービスへルーティングする 「単一のエントリーポイント(リバースプロキシ)」 です。 主な役割と機能 * 認証・認可 (Authentication & Authorization): 各マイクロサービスで個別に認証を行うのではなく、ゲートウェイで一括してトークン検証(JWTなど)を行います。 * ルーティング (Routing): /api/v1/products は商品サービスへ、/api/v1/orders は注文サービスへ、といったパスベースの振り分けを行います。 * レート制限 (Rate Limiting): 特定のクライアントからの過剰なアクセスを遮断し、バックエンドを保護します。 * ロギング・監視 (Observability): システム全体の入り口として、トラフィックのログを一元的に記録します。 2. APIゲートウェイの課題 APIゲートウェイは非常に便利ですが、システムが複雑化し、さまざまなクライアント(PC Web、モバイルアプリ、スマートウォッチ等)が登場すると、以下の課題が生じます。 1. データの過不足 (Over-fetching / Under-fetching): 画面の小さいモバイルアプリでは少量のデータで十分なのに、PC Web向けに設計されたAPIゲートウェイは大量のデータ(オーバースペックなJSON)を返してしまう。 2. ラウンドトリップの増加: 1つの画面を表示するのに、クライアントが複数のAPI(商品、レビュー、推奨)を個別に呼び出す必要があり、低帯域なモバイル環境で表示速度が低下する。 3. ゲートウェイの肥大化: あらゆるクライアントの要望を1つのAPIゲートウェイで満たそうとすると、共通ゲートウェイのコードが肥大化し、開発のボトルネックになります。 3. BFF (Backend For Frontend) パターン 上記の課題を解決するために考案されたのが、BFF(Backend For Frontend)パターン です。 BFFは、共通のAPIゲートウェイを持つ代わりに、「フロントエンド(クライアント)のタイプごとに専用の中間サーバーを用意する」 設計手法です。 BFFがもたらすメリット * APIの集約 (API Composition): BFFがバックエンドの複数サービスからデータを並行して取得し、クライアントが求める形に1つのレスポンスとしてマージします。クライアント・BFF間の通信は1回で済みます。 * データフォーマットの最適化: モバイル向けには不要なフィールドを削除し、画像の解像度を下げたURLを返却するなど、ペイロードサイズを極小化できます。 * フロントエンド開発者への権限委譲: BFFのコードはフロントエンド開発チームが管理・開発することが多いため、UIの変更に伴うAPIの調整をバックエンドチームに依頼することなく自己完結できます(BFFをNode.jsやGraphQLで実装するのが一般的です)。 まとめ * APIゲートウェイ は、認証やレート制限、ルーティングといった共通処理をエッジで一元管理するリバースプロキシ。 * BFF は、クライアントの種類ごとに個別に用意される中間API層。 * BFFを導入することで、クライアントのネットワーク負荷を劇的に減らし、UI開発のスピードとパフォーマンスを最大化できる。