こんにちは!クラウドの世界へようこそ。第一線でインフラやSRE(サイト信頼性エンジニア)として日々のシステムと格闘していると、「なぜか時々、決まった時間だけ通信がプツリと途切れるんだよね……」という、ちょっぴりホラーな現象に出会うことがあります。
データベースとの接続が急に切れたり、APIの呼び出しがタイムアウトしたり。原因を調べていくと、たいてい行き着くのが今回のお題である「NATゲートウェイのコネクションエージング(タイムアウト)」という仕組みです。
難しそうな名前が並んでいますが、安心してくださいね。一歩ずつ、私たちの身近な世界に置き換えながら優しく紐解いていきましょう!
—
1. パブリックとプライベート、そしてNATゲートウェイの「受付窓口」
私たちがAWSやGCPなどのパブリッククラウドでシステムを構築するとき、セキュリティの観点から「外のインターネットから直接アクセスさせたくないサーバー(プライベートサブネット)」を必ず作ります。データベースサーバーや、バックエンドで黙々と処理をこなすアプリサーバーがこれに当たります。
でも、「外のインターネットにつながる必要がある(例えば、外部のAPIを叩きたい、OSのアップデートをしたい)」ときもありますよね。
ここで登場するのが、NATゲートウェイ(Network Address Translation Gateway)です。
郵便局の本局に例えてみよう
プライベートサブネットにあるサーバーたちを、社内の小さな部署だと想像してください。この部署のスタッフは、外の世界(インターネット)に直接手紙を送ることができません。外に出るには、必ずフロアの代表である「受付窓口(=NATゲートウェイ)」を通る必要があります。
スタッフが外の取引先へ手紙を送るとき、受付窓口はこんなメモをこっそり残します。
> 「〇号室のAさんが、外の〇〇会社へ手紙を送ったな。返事が来たら、ちゃんと〇号室のAさんに渡さなきゃいけないから、私の台帳にメモしておこう」
この台帳が、ネットワークの世界でいう「NATテーブル(コネクション追跡テーブル)」です。この仕組みのおかげで、外のサーバーから返ってきた返事が、ちゃんとプライベートサブネットの正しいサーバーに届くようになっています。
—
2. 「何も話すことがない静かな時間」とNATゲートウェイの記憶力
さて、ここからが本題です。
このNATゲートウェイの受付係の「台帳(メモリ)」は、無限の広さを持っていません。無限にメモを書き続けたら、いつかノートが真っ黒になって新しいメモが書けなくなってしまいますよね。
そこで、クラウドの仕組みではこんなルールが決まっています。
> 「しばらくの間(一定時間)、そのコネクションで何の通信(パケットの往来)もなければ、もうこの仕事は終わったとみなして、台帳からメモを消去(エージング)しちゃいます」
この「何も通信がないまま、忘れ去られるまでの時間」を、一般的にTCPコネクションのエージングタイム(またはタイムアウト時間)と呼びます。
例えば、AWSのNATゲートウェイの場合、TCPの通信でしばらくやり取りが途絶えると、デフォルトでおよそ 350秒(約5.5分) でこのメモが消去されてしまいます。GCPのCloud NATなどでも、同様にアイドルタイムアウトの仕組みが存在します。
「あれ、話の途中だったのに!」という悲劇
ここで、こんなシチュエーションを想像してみてください。
1. プライベートサブネットのアプリサーバーが、外部のデータベースやAPIとTCPでしっかり接続しました。
2. データのやり取りが終わり、その後およそ6分間、「お互いに全くデータを送らない静かな時間」が続きました。
3. NATゲートウェイの受付係は、「もうこの通信は終わったんだな」と判断し、台帳からそのメモを綺麗さっぱり消去しました。
4. その直後、アプリサーバーが急に「あ、そういえばさっきの続きだけどさ!」とデータを送り出しました。
さあ、どうなるでしょうか?
NATゲートウェイの受付係は、もう自分の台帳にそのメモを持っていません。「えっ、どこの誰から来たデータなの? うちの台帳には載っていませんけど!」と、そのパケットを冷たくポイッと捨てて(ドロップして)しまいます。
結果として、アプリケーション側は「あれっ? 相手からの返事がピタッと止まったぞ……?」となり、無情なタイムアウトエラーをむかえることになります。これが、私たちが現場でよく直面する「知らぬ間にコネクションが切れている現象」の正体です。
—
3. 解決の切り札!「キープアライブ(Keep-Alive)」の魔法
「じゃあ、6分以上おしゃべりが途切れないように、ずっと意味のないデータを送り続けなきゃいけないの?」
いいえ、そんな非効率なことをする必要はありません。ここで登場するのが、エンジニアの強い味方「キープアライブ(Keep-Alive)」という仕組みです。
身近な例で言うと、電話でお互いに黙り込んでしまったとき、「もしもし? まだ聞いてる?」と相槌を打つようなものです。「まだ私たちはつながっていますよ、生きていますよ」と、たまに小さな合図を送るわけです。
TCPのネットワークや各種ミドルウェアの設定では、この「生きています信号(キープアライブ)」を一定間隔で自動的に送る機能が備わっています。
—
4. 実務で役立つ!具体的な設定とコード例
それでは、実際にインフラやアプリケーションを構築する際、どのようにこの問題に対策すればよいのか、具体的な設定を見ていきましょう。
① アプリケーション(データベース接続:Python / SQLAlchemyの例)
例えば、Pythonから外部のクラウドデータベースなどに接続する際、コネクションプールが古いまま放置されて切断されるのを防ぐため、ドライバー側に「定期的に死活確認(プローブ)を送る」設定を入れます。
from sqlalchemy import create_engine
# データベース接続エンジンの作成
# pool_pre_pingをTrueに設定することで、SQLを実行する前に
# コネクションが生きているかを自動で確認し、切れていれば再接続してくれます
engine = create_engine(
"postgresql://username:password@your-database-endpoint:5432/somedb",
pool_pre_ping=True, # コネクションの生存確認を有効化
pool_recycle=300, # 300秒(5分)経過したコネクションは安全のために張り直す
)
connection = engine.connect()
# ここで安全にクエリを実行できます
② Linux OSレベルのTCPキープアライブ設定
アプリケーションだけでなく、OS(Linux)レベルでTCPコネクション自体のキープアライブを調整することも可能です。/etc/sysctl.conf などに以下のようなパラメータを設定します。
# コネクションが無音になってから、最初にキープアライブパケットを送るまでの時間(秒)
# デフォルトは通常7200秒(2時間)ですが、NAT環境では短くすることが多いです
net.ipv4.tcp_keepalive_time = 120
ニト# キープアライブパケットを送る間隔(秒)
net.ipv4.tcp_keepalive_intvl = 30
# 応答がないと判断してコネクションを切断するまでのリトライ回数
net.ipv4.tcp_keepalive_probes = 5
※上記の設定を行うことで、無音状態が120秒続いたあとに自動で「生きてる?」というパケットが流れ、NATゲートウェイのタイマーをリフレッシュ(延命)させることができます。
—
5. まとめ:目に見えないパケットの旅路を想像しよう
今回は、NATゲートウェイのコネクションエージング処理と、TCPタイムアウトの切なすぎる関係についてお話ししました。
- プライベートサブネットから外に出る通信は、NATゲートウェイの「台帳(テーブル)」にメモされる。
- 一定時間(AWSなら約350秒など)無言の状態が続くと、そのメモは容赦なく消去されてしまう。
- その結果、久しぶりに通信しようとしたときにパケットが迷子になり、タイムアウトを引き起こす。
- キープアライブを適切に設定して、定期的に「ここにいますよ」と相槌を打つことで、このトラブルをスマートに防ぐことができる。
インフラやネットワークの世界は、目に見えないからこそ、こうした背後の仕組み(郵便局の受付や、電話の相槌など)をイメージできるかどうかが、優れたエンジニアへの大きな一歩になります。
「なぜこの設定が必要なんだっけ?」と迷ったときは、ぜひ今回の郵便配達のストーリーを思い出してみてくださいね。現場でのトラブルシューティングが、少しでも楽しく、スムーズになりますように!
コメント