【実務・中級編】Connection: keep-aliveヘッダーによる持続的接続の管理 – HTTPプロトコル・通信規格実践ガイド

HTTP/1.1の「Keep-Alive」を制する者は、Webパフォーマンスを制す

ネットワークの世界へようこそ。若手エンジニアからよく受ける質問に、「なぜWeb APIのレスポンスが遅いのか?」というものがある。コードのロジックを疑う前に、まずは「TCPコネクションの確立」という、目に見えないコストに目を向けてほしい。

HTTP/1.0時代の悪夢は、リクエストのたびに「3ウェイ・ハンドシェイク」を行い、TCPの遅延を食らっていたことだ。これを解決したのが、HTTP/1.1で標準化された`Connection: keep-alive`だ。今日は、この持続的接続の裏側を、現場の視点で解剖しよう。

—

1. なぜ「使い回し」が最強なのか?

TCPコネクションの確立には、SYN/SYN-ACK/ACKという往復のやり取りが必要だ。さらにTLS(HTTPS)となれば、証明書の交換や鍵共有のハンドシェイクが加わる。これが毎回発生すると、RRT(Round Trip Time)が数回分、確実にロスする。

`Keep-Alive`の恩恵は、一度確立した「パイプ」を閉じずに、連続するリクエストで再利用することにある。これにより、2回目以降のリクエストではハンドシェイクのコストをゼロにできる。これが、現代のWeb APIにおける「レスポンスのキレ」を生む正体だ。

—

2. 現場で意識すべきパラメーター:TimeoutとMax

サーバー側(NginxやApacheなど)で設定するKeep-Aliveのパラメーターには、主に2つの重要な指標がある。

  • `keepalive_timeout`: TCP接続を維持する秒数。
  • `keepalive_requests`: 1つのコネクションで処理できる最大リクエスト数。

これを適切に設定しないと、サーバーのリソースが「待ち状態」のコネクションで溢れ、いわゆる「コネクション枯渇」という致命的な障害を招く。

Nginxでの設定例

http {
# 接続を維持する秒数。長すぎるとアイドル状態のコネクションが溜まる。
# 5〜15秒程度が現代的なWebサービスの妥当なラインだ。
keepalive_timeout 15s;

# 1つのコネクションで処理する上限。高負荷時にはこのチューニングが効く。
keepalive_requests 1000;
}

—

3. 実践:コネクション再利用を確認する

理論だけでなく、自分の手で確認しよう。`curl`コマンドを使って、HTTP/1.1の接続が維持されているかを可視化する。

-v で詳細を表示。Connection: keep-alive ヘッダーに注目せよ
curl -v -o /dev/null http://example.com/api/data

出力結果の中に、`Connection #0 left intact`という文字列があれば、それは成功の証だ。TCPコネクションが切断されず、次のリクエストを待っている状態を示している。

Pythonでの実装例(requestsライブラリ)

PythonでWeb APIを叩く際、`requests.Session()`を使わないエンジニアは、現場では「素人」と見なされる。なぜなら、デフォルトではコネクションのプール機能が有効にならないからだ。

import requests

Sessionオブジェクトを使うことで、自動的にKeep-Aliveが有効になる
session = requests.Session()

複数回のAPIコールでも、TCP接続は再利用され続ける
for i in range(5):
response = session.get(“https://api.example.com/v1/resource”)
print(f”Status: {response.status_code}”)

—

4. 現場の教訓:トラブルシュートの極意

「Keep-Aliveしているはずなのに速度が出ない」という相談を受けたとき、私はまず以下の3点をチェックする。

1. クライアント側の実装ミス: セッションを使い回さず、ループのたびに新しいクライアントインスタンスを生成していないか?
2. プロキシ/ロードバランサーの介入: 前段のL7ロードバランサーがKeep-Aliveを強制切断していないか?(設定で`keepalive`を明示的にONにする必要がある)
3. タイムアウトの不一致: サーバー側の`keepalive_timeout`よりも、クライアント側のタイムアウトが短いと、通信の途中でRSTパケットが飛び交うことになる。

デバッグのヒント

Wiresharkや`tcpdump`でパケットをキャプチャしたとき、同じTCPポート番号(送信元ポート)で複数のHTTPリクエストが流れていれば、Keep-Aliveは正しく機能している。逆に、リクエストごとにポート番号がコロコロ変わっているなら、それは「毎回コネクションを捨てている」サインだ。

—

最後に

Keep-Aliveは、ネットワークの「効率」を司る心臓部だ。特に高頻度で小さなリクエストを投げるマイクロサービス間通信では、この設定一つでレイテンシが数十ミリ秒〜数百ミリ秒改善することも珍しくない。

もし君がインフラやバックエンドの設計を任されているなら、単に「動くもの」を作るのではなく、「効率よく流れるネットワーク」を設計してほしい。パケットの流れを想像できるようになれば、君はもう一段上のエンジニアだ。

次は、HTTP/2の「多重化」によるパラダイムシフトについて話すとしよう。あれはまた、Keep-Aliveとは全く別の、もっとエキサイティングな世界だよ。

コメント

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