Long Polling は、サーバーが新しいデータが利用可能になるかタイムアウトが切れるまでHTTPリクエストを開いたままにするクライアント-サーバー間インタラクション技法です。定期的なポーリングとは異なり、サーバーは即座に空の応答を返さず、データをクライアントに送信するイベントの発生を待ちます。MDN Web Docs, 2024によると、Long PollingはWebSocketが利用できないか過剰なリアルタイムアプリケーションにとって人気のあるソリューションであり続けています。
重要なポイント
Long Polling はクライアント-サーバーアーキテクチャにおける通信パターンであり、クライアントがHTTPリクエストを開始し、サーバーは新しいデータが利用可能になるか指定されたタイムアウトが切れるまで応答の送信を遅延します。応答を受信した後、クライアントは即座に次のリクエストを送信し、継続的な接続の効果を生み出します。
Long Polling技法は、空のHTTPリクエストの数を減らすためにShort Pollingの進化的発展として登場しました。従来のポーリングでは、クライアントはN秒ごとにリクエストを送信し、サーバーは新しいデータがない場合でも応答します。Long Pollingでは、サーバーは接続保持メカニズムを使用し、無駄なトラフィックを劇的に削減します。
2011年にWebSocketが登場する前は、Long Pollingがウェブ上のリアルタイム通信の主要な方法でした。FacebookやGmailなどの企業は、2010年代初頭にチャットや通知にこの技法を使用していました。High Performance Browser Networking(Grigorik, 2013)によると、Long Pollingは当時の主要なウェブアプリケーションにおけるすべてのリアルタイム接続の最大95%を処理していました。
クライアントはサーバーに標準的なHTTPリクエストを送信します。リクエストを受信すると、サーバーは即座に応答を返さず、リクエストを待機キューに配置します。サーバーでイベント(新しいメッセージ、データ変更)が発生すると、サーバーは応答を生成してクライアントに送信します。応答を受信すると、クライアントは即座に新しいLong Pollingリクエストを作成し、サイクルが繰り返されます。
Long Polling は以下の一連のステップに従って動作します。クライアントはサーバーエンドポイントにHTTP GETリクエストを送信します。リクエストを受信すると、サーバーはイベントキューに新しいデータがあるか確認します。データがない場合、サーバーはリクエストを待機状態に保持し、即座に応答を送信しません。保持メカニズムはサーバーの実装に依存します — ほとんどの場合、コールバックを使用した非同期処理やイベント駆動型アーキテクチャが使用されます。
サーバー側でイベントが発生すると(例えば、ユーザーがチャットでメッセージを送信した)、サーバーはこのデータを含むボディを持つHTTP応答を生成し、接続を終了します。クライアントは応答を受信し、データを処理して即座に新しいリクエストを開始します。待機期間中にデータが現れなかった場合、サーバーはタイムアウトの満了後に空の応答を送信し、クライアントも接続を再確立します。タイムアウトは通常、負荷と遅延のバランスを取るために30〜60秒です。
Long Pollingの主要な設定パラメータは待機タイムアウトです。短すぎるタイムアウト(10秒未満)はリクエスト数の増加につながり、技法をShort Pollingに近づけます。長すぎるタイムアウト(120秒以上)は、中間プロキシやロードバランサーによる接続切断を引き起こす可能性があります。ほとんどのシナリオで推奨される値は30〜45秒です。
1回のLong Pollingリクエスト中にサーバーで複数のイベントが発生した場合、サーバーはそれらすべてを1つの応答で送信するか、クライアント側でイベントキューを編成する必要があります。このために、イベントバッファリングが使用されます:サーバーはリクエストの保持時間中に発生したイベントを蓄積し、応答ボディ内のデータ配列として送信します。
最新のFetch APIを使用したクライアント側のシンプルなLong Polling実装を見てみましょう。クライアント関数はリクエストを送信し、応答を受信した後に再帰的に自身を呼び出します。
async function longPoll(url) {
try {
const response = await fetch(url);
const data = await response.json();
handleData(data);
longPoll(url);
} catch (error) {
console.error("Long Polling エラー", error);
setTimeout(() => longPoll(url), 3000);
}
}
function handleData(data) {
if (data.events && data.events.length > 0) {
data.events.forEach(event => {
console.log("新しいイベント:", event);
});
}
}
longPoll("/api/events");
このコードは無限のLong Pollingループを作成します:応答を受信した後、関数は即座に新しいリクエストを送信します。接続エラーの場合、サーバーへの雪崩的な負荷を避けるために、再試行前に3秒の遅延が設定されます。
サーバー側では、イベントが発生するかタイムアウトが切れるまでリクエストを保持する必要があります。Node.jsでのEventEmitterを使用した実装例がこのメカニズムを示しています。
const express = require("express");
const EventEmitter = require("events");
const app = express();
const eventBus = new EventEmitter();
app.get("/api/events", (req, res) => {
const timeout = setTimeout(() => {
res.json({ events: [] });
}, 30000);
eventBus.once("new-event", (data) => {
clearTimeout(timeout);
res.json({ events: [data] });
});
});
app.post("/api/events", (req, res) => {
eventBus.emit("new-event", req.body);
res.send({ status: "ok" });
});
app.listen(3000);
サーバー部分はEventEmitterを使用して、新しいデータが現れたときに待機中のLong Polling接続に通知します。30秒のタイムアウトに達すると、サーバーは空のイベント配列を返し、クライアントは新しいリクエストを作成します。
Long Polling は、リアルタイムデータ配信が必要だが、技術的またはインフラストラクチャ上の理由でWebSocketの使用が不可能なシナリオで使用されます。最も一般的なケースは、WebSocket接続をブロックする企業プロキシやファイアウォール、およびサーバー側でのプロトコルサポートが制限された環境です。
Long Pollingを選択する主な要因 は後方互換性です。すべてのHTTPクライアントとサーバーがこの方法をサポートしており、追加の依存関係なしにリアルタイム機能のための普遍的なソリューションとなっています。HTTP Archive(2024)によると、約8%のウェブサイトが基本的なリアルタイム機能にLong Pollingを使用し続けています。
Long Polling とShort Pollingは同じ問題(サーバーからクライアントへのデータ配信)を解決しますが、メカニズムと効率性において根本的に異なります。Short Pollingは固定のポーリング間隔を使用し、クライアントはサーバーに新しいデータが現れたかどうかに関係なく、等しい時間間隔でHTTPリクエストを送信します。
| 特性 | Long Polling | Short Polling |
|---|---|---|
| 応答の開始 | サーバーがイベント時にデータを送信 | サーバーが各クライアントリクエストに応答 |
| 配信遅延 | 最小、最大1秒 | ポーリング間隔に依存、3〜60秒 |
| リクエスト数 | イベントまたはタイムアウトごとに1リクエスト | 単位時間あたりNリクエスト(固定) |
| アイドル時のトラフィック | 低い(1つの開いたリクエスト) | 高い(N秒ごとのリクエスト) |
| サーバー負荷 | 接続の保持 | 頻繁なリクエストの処理 |
| 実装の複雑さ | 中程度(非同期処理) | 低い(通常のHTTPリクエスト) |
Short Polling は実装が簡単ですが、同じデータ更新頻度でサーバーとネットワークにかなり大きな負荷を生み出します。5秒未満の遅延が必要な場合、Short Pollingは1分間に数十のリクエストを生成しますが、Long Pollingはイベントまたはタイムアウトごとに1つのリクエストを使用します。イベントがまれなアプリケーションの場合、Long Pollingはトラフィックの点で桁違いに効率的です。
WebSocket は、最初のHTTPハンドシェイク後にTCP上で動作する完全な双方向リアルタイムプロトコルです。Long Pollingとは異なり、WebSocketは単一の永続的な接続を確立し、サーバーが新しいHTTPリクエストを作成せずにいつでもクライアントにデータを送信できるようにします。
Long PollingとWebSocketの選択は、いくつかの要因によって異なります。互換性:Long Pollingは任意のプロキシやファイアウォールを介して動作しますが、WebSocketは企業ネットワークによってブロックされる可能性があります。パフォーマンス:WebSocketはオーバーヘッドが低く(完全なHTTPヘッダーに対して1フレームあたり2バイト)、高いメッセージ頻度で重要です。スケーラビリティ:Long Pollingは多数の接続を保持するため、サーバー側でより多くのリソースを必要としますが、WebSocketはセッションごとに固定の接続を使用します。
Mozilla Developer Network(2024)によると、WebSocketは 2011〜2015バージョン以降のすべての最新ブラウザでサポートされていますが、企業プロキシ(例:Symantec Blue Coat)は15〜20%の企業ネットワークでそれをブロックし続けており、Long Pollingをフォールバックソリューションとして関連性のあるものにしています。
よくある質問
Long Polling とは、クライアントがサーバーに「新しいデータが利用可能になったら応答してください」と依頼し、サーバーがイベントを待って接続を開いたままにするものです。データが現れるとすぐにサーバーが応答し、クライアントはすぐに同じ質問を再度行います。
Short Polling では、クライアントはデータがあるかどうかに関係なく、N秒ごとにサーバーに問い合わせます。Long Pollingでは、クライアントは一度問い合わせ、サーバーはデータが実際に利用可能になったときにのみ応答します。Long Pollingは空のリクエストが少なく、ネットワーク負荷を軽減します。
Long Pollingは、WebSocketが利用できない場合に使用する必要があります:非HTTPプロトコルをブロックする企業ネットワーク、古いブラウザとの後方互換性が必要な場合、またはホスティング側に制限がある場合。WebSocketは高頻度のデータ交換により効率的です。
Long Pollingの推奨タイムアウト は30〜45秒です。低い値(10〜15秒)はリクエスト数を増加させ、高い値(60秒以上)は中間ロードバランサーによる接続切断のリスクがあります。タイムアウト値はネットワークアーキテクチャとレイテンシ要件によって異なります。
Long Pollingの主な欠点 は、数千の接続を保持する際のサーバーでの高いメモリ消費、水平方向のスケーリングの困難さ(集中イベントキューが必要)、および真の双方向通信の欠如です — サーバーにデータを送信するには別個のPOSTリクエストが必要です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。