NATゲートウェイの「沈黙」を解き明かす:VPCフローログとAthenaによるSNAT枯渇の深層解析
インフラエンジニアにとって、NATゲートウェイ(NATGW)は「外の世界へ繋ぐための黒子」ですが、大規模なマイクロサービス運用において、これほど厄介なボトルネックもありません。特に、突然の Connection Timeout やパケットの REJECT が発生した際、多くの現場が「NATGWのスペック不足」という安易な結論に飛びつきがちです。
しかし、現実はもっとシビアです。その正体は、ほとんどの場合「SNAT(ソースNAT)ポートの枯渇」です。今回は、VPCフローログを武器に、パケットの挙動を可視化し、カーネルレベルのチューニングとアーキテクチャ最適化でこの難所を乗り越えるための実戦的な知見を共有します。
—
1. なぜ「NATGWのポート」が消えるのか?
NATGWは、プライベートサブネット内のリソースから送られてくる膨大なプライベートIPのパケットを、自身のパブリックIPへと変換します。この際、5タプル(送信元IP、送信元ポート、宛先IP、宛先ポート、プロトコル)を追跡するために、ポート番号を割り当てます。
問題は、この「変換後のポート番号(Ephemeral Port)」が65,535個しかない点です。同一の宛先IP/ポートに対して短時間に膨大なセッションを張ると、ポートの解放(TIME_WAIT)が追いつかず、カーネルは送信元ポートを枯渇させ、パケットをドロップします。
VPCフローログで「現場」を覗く
まずは、Athenaを使って、何がこの枯渇を引き起こしているのかを特定しましょう。フローログには、REJECT されたパケットや、異常に高いバイト数を叩き出している送信元IPが刻まれています。
-- NATゲートウェイのインターフェースIDを指定して、REJECTされたパケットを抽出
SELECT
srcaddr,
dstaddr,
dstport,
protocol,
count(*) as reject_count
FROM vpc_flow_logs
WHERE interface_id = 'eni-xxxxxxxxxxxxxxxxx'
AND action = 'REJECT'
AND start > to_unixtime(now() - interval '1' hour)
GROUP BY srcaddr, dstaddr, dstport, protocol
ORDER BY reject_count DESC;
ここで dstport が特定の外部APIサーバー(例: 443)に集中している場合、コネクションプーリングが機能していない、あるいはKeep-Aliveが無視されているという「アプリケーション側の設計ミス」が露呈します。
—
2. ネットワーク層の最適化:RTTとTCPバッファ
アプリケーション側でコネクションを再利用できない場合、Linuxカーネルレベルのネットワークチューニングが最後の砦となります。
TCPバッファの最適化
高遅延環境や大容量通信では、デフォルトのTCPウィンドウサイズでは転送効率が頭打ちになります。/etc/sysctl.conf で以下のチューニングを検討してください。
# TCPウィンドウサイズの拡大:高帯域・高遅延ネットワークでのスループット向上
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# TIME_WAITを効率化し、ポート再利用を促進
net.ipv4.tcp_tw_reuse = 1
# 送信元ポート範囲を拡大(最大64511まで)
net.ipv4.ip_local_port_range = 1024 65535
特に net.ipv4.tcp_tw_reuse は、TIME_WAIT 状態のソケットを新しいコネクションに再利用可能にするための魔法の杖です。ただし、厳密なTCP仕様からは逸脱する可能性があるため、負荷試験での慎重な検証が必要です。
—
3. アプリケーション層の「見えざる」コスト:TLSハンドシェイク
ネットワークトラフィックの多くはTLSによって暗号化されています。TLSハンドシェイクは、RTT(往復遅延時間)を2回消費します。ここで、TLS 1.3への移行は必須です。
- TLS 1.3の採用: 0-RTT(Zero Round Trip Time)Resumptionを使用することで、以前接続したサーバーに対して、最初のパケットから暗号化データペイロードを送信できます。これにより、ハンドシェイクの遅延を劇的に削減可能です。
- ヘッダー圧縮: HTTP/2またはHTTP/3 (QUIC) を導入しましょう。特にQUICはUDPベースであり、TCPのヘッドオブラインブロッキングを回避しつつ、NATGW上のステートフルなポート制限を(設計次第では)より柔軟に扱える可能性があります。
—
4. 根本解決:アーキテクチャの再設計
もし、フローログの解析結果が「特定のAPIへの過剰なリクエスト」を示しているなら、設定変更だけで解決しようとするのは限界です。
1. VPCエンドポイントの活用: AWSサービス(S3やDynamoDBなど)へのアクセスなら、NATGWを通す必要はありません。VPCエンドポイントを経由することで、NATGWのポート制限から解放され、トラフィックコストも削減できます。
2. プロキシの導入: NATGWの手前に透過プロキシやコネクションプール層(Envoyなど)を配置し、外部との接続を「集約」します。これにより、クライアントからの数千の接続を、プロキシからの数十の接続へと多重化(Multiplexing)できます。
まとめ:SREとしての視点
VPCフローログは単なるログではなく、ネットワークの「鼓動」そのものです。REJECT されたパケットを見たとき、それを単なる「失敗」と捉えるか、あるいは「アプリケーションが限界を超えて成長しようとしているサイン」と捉えるか。
優れたアーキテクトは、ログの行間から、背後のパケットがどのようにカーネルのバッファを埋め、NATGWのステートテーブルを圧迫しているかを読み解きます。技術は常に「制約」の中で最適化を求めるものです。その制約を理解し、フローログという確実な証拠を持って戦うことこそが、安定した高可用性インフラを築く唯一の道なのです。
コメント