ロングポーリング徹底解説:基本動作からComet・WebSocket・SSEとの比較、実装ポイントとスケーリング戦略まで
ロングポーリングとは — 概要と基本動作
ロングポーリング(long polling)は、クライアントとサーバー間で「疑似的に」リアルタイム通信を実現する手法の一つです。クライアントがサーバーへリクエスト(通常は HTTP の GET)を送信し、サーバーは即座に応答せず、イベントが発生するまで接続を保持します。イベントが発生した時点でサーバーはレスポンスを返し、クライアントはレスポンスを受け取ると直ちに同じリクエストを再発行して待機状態に戻る、というサイクルを繰り返します。
なぜ「ロング」なのか・Comet との関係
従来の短い間隔でポーリングする方式(短ポーリング)と比べ、ロングポーリングはサーバーがイベントの発生を待つためリクエストが長時間オープンする点が特徴です。ロングポーリングは「Comet」と総称されるリアルタイム技術群の一つで、同じカテゴリにサーバー側ストリーミング(HTTP ストリーミング)や Server-Sent Events(SSE)などがあります。
基本的な処理フロー
- クライアントは /events などのエンドポイントに HTTP リクエストを送る。
- サーバーはイベントが発生するまでリクエストをブロックし、接続を保持する(あるいは内部で待ち受けのキューに登録する)。
- イベントが発生したらサーバーはレスポンス(通常は JSON)を返し、接続を終了する。
- クライアントはレスポンス受信後、すぐに次のリクエストを発行して待ち受けを再開する。
- 一定時間イベントが発生しなかった場合、サーバーはタイムアウト応答(空レスポンスや 204 など)を返し、クライアントは再試行する。
短ポーリングとの比較
- 短ポーリング:クライアントが一定間隔(例:5秒)で定期的にリクエストを送る。サーバーは即座にレスポンスを返す。実装は簡単だが、無駄なリクエストが多く遅延が固定化される。
- ロングポーリング:イベント発生時に即座にレスポンスを返すため、平均レイテンシは短ポーリングより小さい。リクエスト回数は減るがオープン接続が増えるためサーバー・プロキシ側の資源消費に注意が必要。
WebSocket / SSE と比較したメリット・デメリット
リアルタイム通信の選択肢として WebSocket、SSE(Server-Sent Events)、ロングポーリングがあり、それぞれ長所短所があります。
- WebSocket:双方向通信が可能で低レイテンシ。接続確立後は軽量にメッセージ送受信できる。ただしプロキシや古いネットワーク環境でブロックされることがあり、サーバー側で専用の対応(ハンドリング)が必要。
- SSE:サーバー→クライアントの一方向ストリーミング向け。HTTP ベースで自動再接続等の機能があり実装が簡単。バイナリデータの扱いが不得意で、双方向が必要な場面には不向き。
- ロングポーリング:HTTP ベースで互換性が高く、WebSocket が利用できない環境でも動作する。クライアント側は通常の HTTP クライアントで対応可能。だが多数の同時接続を長時間保持するため、スケールやタイムアウト管理が課題になる。
実装上の注意点(サーバー側)
- 接続数とリソース:各接続はソケットやファイルディスクリプタ、サーバーの内部キューを消費する。スレッドモデルのサーバー(同期ブロッキング)ではスレッド数がネックになりやすく、ノンブロッキング(イベントループ)や async フレームワークが有利。
- タイムアウト設定:多くのリバースプロキシやロードバランサーはアイドル接続にタイムアウトを設定している(例:nginx の proxy_read_timeout のデフォルトは 60 秒、AWS ALB のアイドルタイムアウトは通常 60 秒、Cloudflare の HTTP レスポンスは 100 秒制限があるなど)。これらより短い応答周期か、途中でハートビートを返す設計が必要。
- コネクション管理:イベント待ちリクエストは内部で登録しておき、イベント発生時にその登録リストを検索して該当クライアントへレスポンスを投げる設計が一般的。キューや pub/sub を用いると複数サーバー間での実装が楽になる(Redis Pub/Sub、Kafka、メッセージングシステム等)。
- 負荷分散:セッション固有のイベント通知が必要な場合、sticky セッションやユーザーIDをキーにしたメッセージ配信基盤が必要になる。スケールアウト時は中央のメッセージブローカーを介することを検討する。
実装上の注意点(クライアント側)
- 再接続戦略:サーバーが切断した場合やネットワークが切れた場合に備え、指数バックオフ+ジッター(exponential backoff with jitter)を用いるのが推奨される。短時間に大量の再接続を行わないようにする。
- 認証・認可:長時間接続でトークンが期限切れになることがある。アクセストークン更新(リフレッシュ)や接続時に有効な認証方式を採る。
- CORS と安全性:ブラウザから利用する場合、適切な CORS 設定が必要。長い GET を使うことが多いため CSRF の影響は相対的に低いが、ヘッダーにトークンを載せる等で権限チェックは必須。
タイムアウトとハートビート戦略
多くのインフラは接続が「無応答」だと見なして切断するため、サーバーは長時間応答しない場合でも一定周期で空レスポンスや軽いハートビート(空 JSON や特別なステータス)を送って接続が生きていることを示す設計にするか、各種タイムアウトより短い期間で応答→再接続のサイクルを回す必要があります。
スケーリングとアーキテクチャの考え方
- 単一サーバーでは「同時オープン接続数」がボトルネックになる。イベントループ(例:Node.js、asyncio)や非同期フレームワークでスケールするのが一般的。
- 水平スケールする場合は、イベントをどのサーバーが消化しているかの情報を共有するためのメッセージブローカー(Redis Pub/Sub、Kafka、RabbitMQ など)が役に立つ。
- 大規模な通知基盤ではプッシュ配送を専門にするサブシステム(通知サービス)を設け、バックプレッシャーや遅延の管理を中央で行うと運用が容易になる。
実践的な実装例(擬似コード)
以下は概念的な Node.js ライクの擬似フローです(実運用ではエラーハンドリングやタイムアウト管理を加えること)。
- サーバー側:リクエスト受信時にユーザーごとの待ち受けリストにレスポンスオブジェクトを保存。イベント発生時に該当リストからレスポンスを書き込み end する。
- クライアント側:レスポンス受信後に即座に次のリクエストを発行する。接続失敗時はバックオフで再試行。
よくある落とし穴とトラブルシューティング
- プロキシや CDN による切断:応答が長時間来ないと切断されるため、インフラのタイムアウト値を確認する。Cloudflare は 100 秒のレスポンス上限などの制限がある。
- スロースタートの「同時再接続」問題:サーバー再起動後や障害復旧時に全クライアントが同時に再接続するとスパイクが発生する。ジッター付きの再接続戦略で回避する。
- 不要なデータ転送:イベントが頻繁にない場合でも短いタイムアウトで頻繁に再接続するとオーバーヘッドが大きくなる。適切なタイムアウトとイベント設計が重要。
ユースケース
- チャットアプリのメッセージ受信(WebSocket が使えない環境での代替)
- ユーザー毎の通知・アラート配信
- ブラウザでのリアルタイムアップデート(簡単な株価やステータス表示)
- レガシー環境でのリアルタイム要件対応(ファイアウォールやプロキシで WebSocket が遮断される場合)
まとめ — いつロングポーリングを選ぶべきか
ロングポーリングは互換性が高く、実装も比較的シンプルで「WebSocket が使えないがリアルタイム性が必要」な場合に有効です。一方で、同時接続数が大きくなるとサーバーやプロキシのリソースを消費しやすいため、スケールやタイムアウト、再接続戦略を丁寧に設計する必要があります。可能であれば WebSocket(双方向)や SSE(サーバー→クライアント一方向)といった専用のリアルタイム手段と比較検討し、利用環境やインフラ制約に応じて最適な方式を選びましょう。
参考文献
- Comet (programming) — Wikipedia
- Using server-sent events — MDN Web Docs
- WebSockets — MDN Web Docs
- ngx_http_proxy_module — proxy_read_timeout — Nginx Documentation
- Elastic Load Balancing — Idle timeouts — AWS Documentation
- Cloudflare — Product and Service Limits


