Tech Learning Daily

2026-07-27 (Mon) — 第 11 号
AI が毎朝届ける、ソフトウェア技術の基礎解説
Network 🌿 基礎 ⏱ 約 8 分

ALB と NLB、同じ「ロードバランサー」なのに何が違うのか?

AWS でロードバランサーを作るとき、コンソールには Application Load Balancer と Network Load Balancer という 2 つの選択肢が並ぶ。多くの人は「HTTP なら ALB、それ以外は NLB」という程度の理解でどちらかを選び、そのまま動くので深く考えずに済ませてしまう。だがこの 2 つは単なる名前違いではなく、OSI 参照モデルのどの層でパケットを見ているかという設計思想からして別物だ。

🎯 3 行まとめ
  • ALB はアプリケーション層(L7)で HTTP の中身を読んで振り分け、NLB はトランスポート層(L4)で TCP/UDP のコネクションだけを見て振り分ける
  • NLB は接続を素通しに近い形で扱うぶん送信元 IP を保持しやすく静的 IP も持てるが、ALB はパスやヘッダーに基づくルーティングと WAF 連携ができる代わりに接続を一度終端する
  • 「HTTP か否か」だけでなく、静的 IP の要否・送信元 IP 保持の要否・秒間リクエスト数の規模まで見て選ぶと、あとから設定変更で悩む場面が減る

L4 と L7、ロードバランサーは「どこを読んで」振り分けているのか

OSI 参照モデルは通信の役割を 7 つの層に分けて整理したモデルで、下から 4 番目がトランスポート層(L4)、7 番目がアプリケーション層(L7)にあたる。L4 では TCP・UDP がポート番号とコネクションの管理を担い、その上に乗る L7 で HTTP・TLS・FTP といった具体的なアプリケーションプロトコルが動く。ロードバランサーが「L4 で動く」「L7 で動く」というのは、振り分け先を決めるときにどの層までの情報を読むかの違いを指している。

L4 ロードバランサーは送信元 IP・送信元ポート・宛先 IP・宛先ポートといった接続情報だけを見て、あるコネクションをどのターゲットに送るかを決める。中身が HTTP なのか gRPC なのか独自バイナリプロトコルなのかは関知しない。一方 L7 ロードバランサーは TCP 接続をいったん自分で終端し、その上に流れる HTTP リクエストの中身(パス・ヘッダー・Cookie など)まで読んでから、どのターゲットに転送するかを決める。当然、読む情報が増えるぶん処理は重くなるが、その分できることも増える。

🍱 たとえるなら

マンションの管理人を思い浮かべてほしい。L4 の管理人は宅配便を「何号室宛か」という宛先ラベルだけ見て各部屋のポストに振り分ける。中身が請求書なのか荷物なのかは開けて確認しない。L7 の管理人はさらに一歩踏み込み、届いた封筒を開封して「経理宛の請求書はこの部署、クレーム対応の手紙は別の部署」と中身の記載内容まで読んでから配る。後者の方が柔軟な仕分けができる代わりに、封を開けて読む手間がかかる。

NLB ― 接続をそのまま流す L4 の特性

AWS の Network Load Balancer(NLB)は OSI モデルの第 4 層で動作し、ターゲットグループは TCP・UDP・TLS・TCP_UDP・QUIC・TCP_QUIC といったプロトコルをサポートする。TCP トラフィックの場合、送信元 IP・送信元ポート・宛先 IP・宛先ポート・TCP シーケンス番号を元にしたフローハッシュ(接続ごとに転送先を一意に決めるハッシュ計算)でターゲットを選び、1 つの TCP コネクションはその接続が生きている間ずっと同じターゲットに送られ続ける。HTTP リクエスト単位ではなく、コネクション単位で経路が固定される点が ALB との大きな違いだ。

NLB はインターネット向け構成にすると、有効化した各アベイラビリティゾーンのサブネットごとに Elastic IP を 1 つ割り当てられ、ロードバランサーに静的 IP アドレスを持たせられる。ALB の IP は動的に変わりうるため、クライアント側で IP をファイアウォールの許可リストに登録するような要件では NLB が候補になる。また、送信元 IP アドレスをそのままターゲットに渡せるかどうかはターゲットグループの種類に依存する仕組みで、インスタンス ID をターゲットにする構成では TCP 接続を終端せず転送するため、アプリケーション側で元のクライアント IP がそのまま見える。

┌────────┐   TCP 接続を維持   ┌────────┐
│ クライアント │ ───────────────▶ │  NLB   │
└────────┘  (中身は見ない)   └───┬────┘
                              │ フローハッシュで
                              │ 固定ターゲットへ
                              ▼
                          ┌────────┐
                          │ ターゲット │
                          └────────┘

ALB ― HTTP の中身で経路を分ける L7 の特性

Application Load Balancer(ALB)は L7 で動作し、クライアントとの接続とターゲットとの接続を別々に終端する。この構造のおかげで、URL パスやホスト名、HTTP ヘッダーの値に応じて転送先のターゲットグループを切り替えるルーティングルールが組める。マイクロサービスで /api/* はサービス A、/admin/* はサービス B、といった振り分けは ALB の得意分野で、NLB にはこの機能はない。ALB はさらに AWS WAF と統合でき、リクエストの中身を見て悪意あるパターンを遮断する仕組みを前段に置ける。これも中身を読める L7 だからこそ実現できる。

設定面では、ALB は接続がアイドル状態のままだとidle_timeout.timeout_seconds属性のデフォルト値 60 秒でクライアントとの接続を切る。長時間のロングポーリングや大きなファイルアップロードを扱うなら、この値を明示的に伸ばさないと想定外の切断が起きる。またターゲットを外す際、処理中のリクエストを完了させるために一定時間「draining」状態を保ってから正式に切り離すデレジストレーション遅延という仕組みがあり、deregistration_delay.timeout_secondsのデフォルトは 300 秒(5 分)だ。デプロイのたびに一部のリクエストが失敗するなら、まずこの値を疑ってよい。

aws elbv2 modify-target-group-attributes \
  --target-group-arn {arn} \
  --attributes Key=deregistration_delay.timeout_seconds,Value=30

もう一つ見落としがちなのがクロスゾーン負荷分散(複数のアベイラビリティゾーンにまたがってリクエストを均等に配るかどうかの設定)のデフォルトが ALB と NLB で逆であることだ。ALB はロードバランサー単位で常時オンで無効化できず、ターゲットグループ単位でのみオフにできる。対して NLB は各ロードバランサーノードが自身のゾーン内のターゲットにしか送らないのがデフォルトで、複数ゾーンへ均等に振りたければ明示的に有効化する必要がある。ゾーンごとのターゲット数が偏っていると、NLB ではこの設定次第で負荷の偏りがそのまま残ることになる。

結局どちらを選ぶのか ― 判断基準を絞る

「Web アプリのフロントに置く」という典型的なユースケースなら、パスベースルーティングと WAF が使える ALB がまず候補になる。判断が割れるのは次の 3 パターンだ。1 つ目は、gRPC 以外の TCP・UDP プロトコル(MQTT・独自バイナリプロトコルなど)を流したい場合で、HTTP を前提にした ALB のルーティングルールは意味を持たないため NLB を選ぶ。2 つ目は、クライアント側の許可リストに固定 IP を登録する必要がある場合で、静的 IP を持てる NLB が要件を満たす。3 つ目は秒間数百万リクエスト級の極端に高いスループットが必要な場合で、コネクションを終端せず転送するだけの NLB の方が処理コストが低い。

逆に「HTTP だから ALB」と決め打ちしても、静的 IP や生の送信元 IP が必要になった時点で構成の見直しを迫られる。実際には ALB をターゲットに持つ NLB を前段に置き、静的 IP と L7 ルーティングを両立させる構成も AWS の公式パターンとして用意されているほどで、両者は排他的な選択肢ではなく組み合わせて使う道具でもある。

💼 実務でどう出会うか

Kubernetes を EKS で動かしていると、Ingress リソースに alb、Service の type: LoadBalancernlb というアノテーションが登場する。前者は AWS Load Balancer Controller が裏で ALB を作り、パスベースのルーティングを Ingress の rules にそのままマッピングする。後者は L4 のまま TCP/UDP をノードまたは Pod に直接流す。この使い分けの背景にあるのが今回見た L4/L7 の違いで、名前だけ覚えていると「なぜ Ingress は ALB 前提の書き方なのに Service は NLB でも動くのか」が繋がらない。

⌨️ 手を動かす(5 分)

L4 は接続の中身を一切解釈せず、L7 は中身を構造として読む、という違いを手元で体感する。ターミナルを 2 つ開く。

# ターミナル 1: 生の TCP リスナーを立てる(L4 目線の世界)
nc -l 8080

# ターミナル 2: HTTP として体裁の整っていないバイト列を送る
printf 'hello, this is not a valid HTTP request at all\r\n' | nc localhost 8080

ターミナル 1 にはそのままの文字列がエコーされるはずだ。TCP はバイト列を届けるだけで、中身が HTTP のリクエストラインとして正しい形式かどうかを一切気にしない。これが L4 の視点である。次に同じリスナーに対して curl -v http://localhost:8080/ を打つと、curl は GET / HTTP/1.1 という構造化されたリクエストラインとヘッダー群を送り込む。ターミナル 1 の出力を見比べると、curl が送った「意味のある構造」を L7 の装置だけが解釈できる理由が分かるはずだ。

🙅 よくある誤解
  • NLB は L4 だから TLS を扱えない — NLB は TLS リスナーもサポートしており、証明書を使って NLB 自身で TLS を終端しターゲットには平文の TCP で転送する構成が組める。L4 か L7 かは「HTTP の中身を読むかどうか」の話であって、暗号化の有無とは別軸の話だ。
  • 機能が多い ALB を使っておけば常に安全 — ALB はコネクションを終端して処理する分だけ NLB よりオーバーヘッドが大きく、極端に高いスループットや非 HTTP プロトコルの前段には向かない。機能の多さと適材適所は別問題である。
  • ALB でも送信元 IP はそのままバックエンドに渡る — ALB はクライアントとの接続とターゲットとの接続を別に終端するため、アプリケーション側から見える接続元は ALB 自身になる。元のクライアント IP は X-Forwarded-For ヘッダー経由でしか分からない。
📖 用語ミニ辞典
OSI 参照モデル
通信の役割を物理層からアプリケーション層まで 7 層に分けて整理したモデル。
トランスポート層(L4)
OSI モデルの第 4 層。TCP・UDP がポート番号とコネクションの管理を担う層。
アプリケーション層(L7)
OSI モデルの第 7 層。HTTP・TLS・FTP など具体的なアプリケーションプロトコルが動く層。
フローハッシュ
送信元・宛先の IP やポートなどから接続ごとに転送先を一意に決めるハッシュ計算方式。
デレジストレーション遅延
ターゲットを切り離す際、処理中のリクエストを完了させるために一定時間 draining 状態を保つ設定。
クロスゾーン負荷分散
複数のアベイラビリティゾーンにまたがってリクエストを均等に振り分けるかどうかの設定。
🔗 もっと深く