【テクニカル・上級編】 GCP Cloud NATの最小ポート数(Min Ports Per VM)自動割当アルゴリズム – クラウド&コンテナネットワーク実践ガイド

Cloud NATの深淵:Min Ports Per VMの自動拡張が支える、高負荷ネットワークの裏側

SREの現場で「NATゲートウェイ」という言葉を聞くと、多くのエンジニアは「ただの出口」だと考えがちです。しかし、GCPのCloud NATを使いこなすアーキテクトにとって、それは「セッションの調停者」であり、パフォーマンスのボトルネックを排除する精密機械そのものです。

今日は、Cloud NATの肝である min_ports_per_vm の自動拡張アルゴリズムと、それがパケットレベルでどのような挙動を支えているのか、現場の視点から掘り下げていきます。

なぜ「ポート不足」がネットワークの死角になるのか

多くのエンジニアが直面する 503 Service Unavailable や Connection Timeout の原因が、実はNATのポート枯渇であることは少なくありません。

TCP/UDPの通信において、ソースポートは 0 から 65535 の範囲しかありません。NATを通る際、外部IPアドレスとソースポートの組み合わせ(5-tuple)でセッションを識別しますが、もし一つのVMが大量の外部APIを叩けば、あっという間にポートを使い切ります。

ここで重要なのが、GCPのCloud NATが提供する「動的ポート割り当て」です。

Min Ports Per VM:静的な縛りからの解放

デフォルト設定では、min_ports_per_vm は 64 です。しかし、トラフィックが急増した際、この値が固定されたままだと、VMはすぐに「ポート不足」に陥ります。

Cloud NATの賢いところは、この値を「最小値」として確保しつつ、必要に応じて自動的に拡張するアルゴリズムを持っている点です。

動的拡張の内部メカニズム

Cloud NATは以下のロジックで動いています。

1. 静的確保: 設定した min_ports_per_vm 分のポートを、VM起動時にそのVM専用として確保します。
2. 動的拡張: 確保したポートを使い切ると、NATはバックグラウンドで「追加のポート」を動的に割り当てます。この拡張は、負荷に応じて max_ports_per_vm の上限まで柔軟に行われます。
3. エンドポイント独立マッピング (Endpoint Independent Mapping): これが極めて重要です。同じソースIPとポートから同じ宛先へ通信する場合、NATは一度割り当てたマッピングを再利用しようとします。これにより、RTTを削減し、ハンドシェイクのオーバーヘッドを最小化します。

パケットレベルの最適化とチューニングの勘所

単に設定をいじるだけでは、極限のパフォーマンスは引き出せません。カーネルレベルのチューニングと組み合わせる必要があります。

TCPバッファとコネクション再利用の戦略

NATを通過するパケットを最適化するためには、クライアント側のOS設定が鍵となります。特に、TIME_WAIT 状態のソケットをどう扱うかが勝負の分かれ目です。

# sysctl.conf での設定例
# TIME_WAIT ソケットを素早く再利用することでポート枯渇を防ぐ
net.ipv4.tcp_tw_reuse = 1

# TCPウィンドウサイズを拡大し、高遅延環境でのスループットを向上させる
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

TLSハンドシェイクのオーバーヘッド回避

Endpoint Independent Mapping の恩恵を最大限に受けるには、HTTP/2 や HTTP/3(QUIC)の活用が必須です。特に Keep-Alive 設定を適切に行い、コネクションを維持することで、NATテーブルのエントリ更新頻度を下げ、SYN パケットの往復を減らすことができます。

実践:Cloud NATの設定と監視

Terraformで構成を管理する場合、以下の設定が「攻め」の定石です。

resource "google_compute_router_nat" "main_nat" {
  name                               = "production-nat"
  router                             = google_compute_router.router.name
  region                             = "asia-northeast1"
  nat_ip_allocate_option             = "AUTO_ONLY"
  source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"

  # 最小ポート数を少し多めに設定し、バースト時のレイテンシを抑える
  min_ports_per_vm = 256 
  
  # 動的拡張を有効化(デフォルトで有効だが明示的に意識する)
  enable_dynamic_port_allocation = true
  max_ports_per_vm               = 65536
}

最後に:SREとして監視すべきメトリクス

Cloud NATを構築した後は、Cloud Monitoringでの監視が全てです。以下のメトリクスは常にダッシュボードに置いてください。

  • nat/allocated_ports_count: VMが現在確保しているポート数。
  • nat/dropped_packets_count: ポート不足で破棄されたパケット。これが 0 でないなら、min_ports_per_vm を上げるか、コネクションの使い回しを再考すべきです。

ネットワークは「繋がって当たり前」の世界です。しかし、その裏側でCloud NATがどれだけの苦労をしてパケットの整合性を保っているか。その理解があるだけで、あなたのインフラの堅牢性は一段上のレベルに到達します。

次回のトラブルシューティングでは、ぜひ tcpdump を使ってNATの内側と外側でマッピングがどう変わっているか確認してみてください。パケットの呼吸が聞こえてくるはずです。

コメント

タイトルとURLをコピーしました