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초입니다.
하나의 Long Polling 요청 중에 서버에서 여러 이벤트가 발생한 경우 서버는 모든 이벤트를 하나의 응답으로 전송하거나 클라이언트 측에서 이벤트 큐를 구성해야 합니다. 이를 위해 이벤트 버퍼링이 사용됩니다. 서버는 요청 유지 중에 발생한 이벤트를 누적하여 응답 본문에 데이터 배열로 전송합니다.
최신 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은 분당 수십 개의 요청을 생성하는 반면 Long Polling은 이벤트 또는 타임아웃당 하나의 요청을 사용합니다. 드문 이벤트가 있는 애플리케이션의 경우 Long Polling이 트래픽 측면에서 훨씬 더 효율적입니다.
WebSocket은 초기 HTTP 핸드셰이크 후 TCP 위에서 작동하는 완전한 양방향 실시간 프로토콜입니다. Long Polling과 달리 WebSocket은 하나의 영구 연결을 설정하고 서버가 새 HTTP 요청을 생성하지 않고도 언제든지 클라이언트에 데이터를 보낼 수 있습니다.
Long Polling과 WebSocket 사이의 선택은 여러 요소에 따라 달라집니다. 호환성: Long Polling은 모든 프록시와 방화벽을 통해 작동하지만 WebSocket은 기업 네트워크에서 차단될 수 있습니다. 성능: WebSocket은 오버헤드가 더 작습니다(전체 HTTP 헤더 대신 프레임당 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은 빈 요청이 더 적게 생성되고 네트워크 부하를 줄입니다.
WebSocket을 사용할 수 없을 때 Long Polling을 사용해야 합니다. 비HTTP 프로토콜을 차단하는 기업 네트워크, 오래된 브라우저와의 하위 호환성이 필요하거나 호스팅 측 제한이 있는 경우입니다. WebSocket은 고주파 데이터 교환에 더 효율적입니다.
권장되는 Long Polling 타임아웃은 30~45초입니다. 더 작은 값(10~15초)은 요청 수를 증가시키고 더 큰 값(60초 이상)은 중간 로드 밸런서에 의한 연결 끊김 위험이 있습니다. 타임아웃 값은 네트워크 아키텍처와 지연 요구 사항에 따라 달라집니다.
Long Polling의 주요 단점은 수천 개의 연결을 유지할 때 서버 메모리 소비가 높고, 수평적 확장이 어렵고(중앙 집중식 이벤트 큐 필요), 진정한 양방향 통신이 부족하다는 점입니다. 서버로 데이터를 보내려면 별도의 POST 요청이 필요합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.