L4 ロードバランサの内部:DSR・コネクション保持
L4 ロードバランサが低遅延・高スループットを出せる理由を、NAT と DSR の経路差、コネクション追跡テーブル、Maglev 一貫性ハッシュの三つから内部動作で理解できる。
- 1.L4 LB は IP とポートだけを見て接続単位で転送し、NAT 方式は往復ともLBを通すが、DSR は戻りトラフィックを LB を介さずクライアントへ直接返す。
- 2.同一接続を必ず同じ実サーバーへ送るため、LB はコネクション追跡テーブルでフローと選択結果を記憶し、表に無いパケットだけハッシュで実サーバーを選ぶ。
- 3.Maglev 等の一貫性ハッシュは、実サーバーの増減や LB の水平分散があっても既存接続の宛先を極力変えず、テーブルが同期していなくても接続を維持する。
L4 ロードバランサが見ているもの
L4 ロードバランサ(LB)は、トランスポート層の情報、すなわち IP アドレスとポート番号だけを見て転送先の実サーバーを決めます。HTTP のパスや Cookie のようなアプリ層の中身は解釈しないため、TLS を終端する必要がなく、CPU 負荷が軽く遅延も小さいのが特徴です。L7 との役割分担はプロキシとロードバランサで整理しています。
ここで決定的に重要なのは、LB は「接続(コネクション)」を単位に動くという点です。1つの TCP 接続を構成するパケット群は、最初から最後まで同じ実サーバーへ届かなければなりません。途中で宛先が変われば、その実サーバーにはシーケンス番号もTCP 状態も存在しない接続のパケットが飛び込み、RST で切られて通信が壊れます。L4 LB の内部設計は、この接続の一貫性をいかに低コストで保つかという一点に集約されます。
NAT 方式:往復ともLBを通す
最も素直な実装が NAT 方式です。クライアントから来たパケットの宛先 IP(LB の VIP=仮想 IP)を、選んだ実サーバーの IP へ書き換えて転送します。戻りパケットも LB を通り、送信元 IP を VIP へ書き戻してからクライアントへ返します。クライアントはあくまで VIP と会話しているつもりで、実サーバーの存在に気づきません。NAT そのものの仕組みはNATを参照してください。
NAT 方式の経路(往路と復路の両方が LB を通る):
client → [dst=VIP] → LB
LB → [dst=realserver IP] → realserver (宛先を書き換え)
realserver → [src=realserver IP] → LB
LB → [src=VIP] → client (送信元を書き戻す)
NAT 方式の弱点は、戻りトラフィックも必ず LB を経由することです。Web の応答は一般にリクエストよりはるかに大きく、ダウンロードや動画配信では復路が支配的になります。その全量が LB を通れば、LB の帯域とパケット処理能力がボトルネックになります。さらに、実サーバーから見える送信元 IP は LB のものになり、クライアントの本来の IP はそのままでは取れません。
NAT は接続ごとにアドレス変換の対応関係を表に持ち、復路でそれを逆引きして送信元を VIP に戻します。もし戻りパケットが LB を通らず実サーバーから直接クライアントへ返ると、クライアントは「VIP へ送ったのに、見知らぬ実サーバー IP から応答が来た」と判断し、その応答を破棄します。NAT の対称性を保つには往復とも同じ LB を通すしかありません。
DSR:戻りを LB に通さない
この復路ボトルネックを外すのが**ダイレクトサーバーリターン(DSR、Direct Server Return)**です。発想は単純で、往路だけ LB を通し、復路は実サーバーからクライアントへ直接返します。応答が LB を素通りしないため、LB は往路のリクエストだけを捌けばよく、桁違いのスループットを扱えます。
実現の鍵は、宛先 IP を書き換えないことです。代表的な L2-DSR では、LB は IP ヘッダを一切変えず、宛先 MAC アドレスだけを実サーバーのものに差し替えて転送します(同一 L2 セグメントが前提)。実サーバーは宛先 IP が VIP のままのパケットを受け取るので、自分の loopback などに VIP を割り当てておき「自分宛て」として処理します。応答の送信元 IP も自然に VIP になり、クライアントから見れば VIP と会話したことになります。トンネル方式(IP-in-IP)では L2 制約を外し、ルータ越しでも DSR を成立させます。
| 観点 | NAT 方式 | DSR 方式 |
|---|---|---|
| 往路 | 宛先 IP を実サーバーへ書き換え | 宛先 MAC のみ差し替え(IP は VIP のまま) |
| 復路 | 必ず LB を経由し src を VIP へ戻す | 実サーバーから client へ直接(LB を通らない) |
| LB の負荷 | 往復の全トラフィック | 往路リクエストのみ |
| 実サーバー側設定 | デフォルトGWを LB に向ける程度 | loopback に VIP 割当+ARP 抑制が必須 |
| クライアント元IP | そのままでは消える | 実サーバーが直接見える |
DSR では複数の実サーバーが同じ VIP を loopback に持ちます。これらが ARP に応答すると、同一セグメント内で VIP に対する MAC が複数現れ、ARP テーブルが汚染されてトラフィックが意図しない先へ飛びます。そのため各実サーバーは VIP について ARP 応答も ARP 要求も出さない設定(Linux なら arp_ignore/arp_announce 相当)が必須です。これを忘れると断続的な接続不能という再現の難しい障害になります。
DSR の制約は、戻りが LB を通らないためにLB が接続の終了を観測できないことです。LB は往路のパケットしか見ないので、TCP の FIN/RST による正常終了を直接は捉えられず、後述するコネクション追跡はタイムアウト主体にならざるを得ません。また、応答を加工できないため L7 的な書き換えはできず、純粋な L4 転送に用途が限られます。
コネクション追跡テーブル
NAT であれ DSR であれ、L4 LB は同一接続を同じ実サーバーへ送り続ける必要があります。これを担うのが**コネクション追跡テーブル(conntrack table)**です。キーは接続を一意に識別する5タプル、値は選択済みの実サーバーです。
conntrack エントリ:
key = (src IP, src port, dst IP, dst port, protocol)
value = 選択した実サーバー, 最終観測時刻, 状態
パケットが届くと、LB はまずこの表を引きます。ヒットすれば記録済みの実サーバーへ即座に転送し、再計算しません。ミスすれば(=新規接続)負荷分散アルゴリズムで実サーバーを選び、結果を表に書き込みます。これにより、たとえ実サーバー集合が後から変わっても、確立済みの接続は最初に選んだ宛先へ固定され続けます。表引きは O(1) のハッシュ参照で、転送のホットパスを軽く保ちます。
このテーブルは無限には保持できないため、各エントリにアイドルタイムアウトを持たせ、一定時間パケットが来ない接続を回収します。TCP では FIN/RST を観測したら短いタイムアウトへ落とし、確立中の接続は長めに保つ、という状態依存の管理が一般的です。DSR では復路(と多くの場合 FIN/RST)が見えないため、この見極めが効かず、アイドルタイムアウトのみで判断します。
コネクション追跡は接続ごとにメモリを消費するため、SYN フラッドのように大量の半開接続を作る攻撃や、極端に多い同時接続でテーブルが溢れることがあります。溢れると新規接続が確立できなくなり、サービス全体が停止します。SYN cookie や接続レート制限、適切なタイムアウト設定でテーブル占有を抑えるのが運用上の要点です。
なぜテーブルだけでは足りないのか
conntrack テーブルは強力ですが、1台の LB の中だけで完結する記憶です。現実の大規模 LB は、可用性とスケールのために複数台を並べ、その手前でECMPやAnycastを使ってトラフィックを各 LB へ分散します。ここで二つの問題が起きます。
一つはLB 群の構成変化です。ECMP は経路(=LB)が増減すると単純なハッシュではフローの割り当てが大きくずれ、確立済み接続のパケットが、その接続のエントリを持たない別の LB へ届きます。届いた LB はテーブルがミスし、新規接続として別の実サーバーを選ぶかもしれません。結果、接続が壊れます。
もう一つは実サーバー集合の変化です。index = hash(5タプル) mod N のような単純剰余では、実サーバー数 N が変わると、ほとんどの接続の割り当て先がずれてしまいます。conntrack でヒットしている既存接続は守られますが、何らかの理由でエントリを失った接続(LB の切り替えやテーブル満杯による追い出し)は、再計算で別サーバーへ飛び、壊れます。
つまり、テーブルがミスしたときのフォールバックとしての実サーバー選択自体が、構成変化に対して安定でなければなりません。ここで一貫性ハッシュが効いてきます。
Maglev と一貫性ハッシュによる接続維持
一貫性ハッシュ(consistent hashing)は、実サーバーの増減で再割り当てされる接続を全体の約 1/N に限定し、影響を受けない接続の宛先を不変に保つ手法です。これにより、conntrack テーブルがミスしても、複数の LB がそれぞれ独立に同じ実サーバーを選べるようになります。テーブルの内容を LB 間で同期しなくても、同じ5タプルなら同じ宛先に落ちるからです。
Google が公表した Maglev は、これをパケット処理速度に耐える形で実装したものです。各 LB は実サーバー集合から決定的に lookup テーブル(固定長の配列で、各スロットが1つの実サーバーを指す)を構築します。転送時は5タプルをハッシュしてスロット番号を引くだけで実サーバーが決まり、ホットパスは単純な配列参照になります。
Maglev の転送(テーブルがミスした場合のフォールバック選択):
slot = hash(5タプル) mod テーブル長
server = lookup[slot]
# lookup テーブルは実サーバー集合から決定的に生成されるため、
# 同じ集合を持つ全 LB が同じ slot から同じ server を導く
Maglev の lookup テーブル生成は、各実サーバーに固有の順列(preference list)を割り当て、ラウンドロビンでスロットを奪い合わせることで、(1) 各サーバーがほぼ均等なスロット数を得る均等性と、(2) サーバーが1台抜けても他のスロット割り当てがほとんど動かない最小撹乱性を両立させます。1台障害時に再割り当てされるスロットは、原則その障害サーバーが持っていた分にほぼ限られます。
実装は「conntrack テーブル」と「一貫性ハッシュ」を二段構えで使うのが定石です。確立済み接続はテーブルのヒットで確実に同じ実サーバーへ固定し、テーブルにエントリが無いパケット(新規接続、別 LB へ流れてきた既存接続)だけ一貫性ハッシュで決める。前者が一貫性の主役、後者は「テーブルが当てにできない瞬間でも宛先がブレない」保険として働きます。この組み合わせで、LB の追加・削除や実サーバーの増減があっても、進行中の接続を最大限維持できます。
頻出の対比は三つ。(1) NAT は往復とも LB を通すので復路がボトルネック、DSR は戻りを LB に通さず実サーバーから直接返すのでスループットが伸びるが、実サーバー側の VIP loopback 割当と ARP 抑制が必須。(2) 接続の一貫性は conntrack テーブル(5タプル→実サーバーの記憶)で保つ。(3) テーブルがミスする瞬間(LB 増減・テーブル満杯)に備え、単純剰余ではなく一貫性ハッシュ(Maglev 等)で、複数 LB が同期なしに同じ宛先を選べるようにする。
まとめ
L4 ロードバランサの内部は、接続の一貫性を低コストで保つという制約から設計が導かれます。NAT 方式は往復とも LB を通して対称性を担保しますが復路がボトルネックになり、DSR は戻りを実サーバーから直接返すことでこの制約を外す代わりに、VIP の loopback 割当・ARP 抑制と、LB が接続終了を観測できないという代償を負います。同一接続を同じ実サーバーへ固定する記憶はコネクション追跡テーブルが担い、テーブルがミスする瞬間に宛先がブレないよう Maglev のような一貫性ハッシュを併用します。NAT と DSR の経路差、conntrack の役割、そして一貫性ハッシュが「テーブル同期なしの宛先一致」をどう実現するかを、それぞれが何を解いているかとセットで押さえることが、L4 LB を正しく設計・運用する鍵になります。
ネットワーク Article
L4 ロードバランサの内部:DSR・コネクション保持を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ロードバランサ
比較で見る軸
難易度: advanced / カテゴリ: ネットワーク / タグ数: 5
導入後に効く点
同一接続を必ず同じ実サーバーへ送るため、LB はコネクション追跡テーブルでフローと選択結果を記憶し、表に無いパケットだけハッシュで実サーバーを選ぶ。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- ネットワーク
- タグ数
- 5
判断チェックリスト
- 自社の用途が「ロードバランサ / L4」に近いか確認する。
- 強みである「L4 LB は IP とポートだけを見て接続単位で転送し、NAT 方式は往復ともLBを通すが、DSR は戻りトラフィックを LB を介さずクライアントへ直接返す。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。