실시간 통신 기술

김진효·2026년 6월 10일

[CS] 면접 대비

목록 보기
6/12
post-thumbnail

채팅이나 대시보드 같이 웹에서 서버와 클라이언트가 실시간으로 데이터를 주고받아야 하는 서비스를 구현할 때, 어떤 기술을 선택하면 좋을지 정리해보고자 한다!

1. Polling

클라이언트가 일정 주기로 서버에 요청을 보내 데이터를 가져오는 방식

✔️ 동작 방식

클라이언트 → 서버: 새 데이터 있나요?
서버 → 클라이언트: 없음
(3초 후)
클라이언트 → 서버: 새 데이터 있나요?
서버 → 클라이언트: 없음
(3초 후)
클라이언트 → 서버: 새 데이터 있나요?
서버 → 클라이언트: 있음! 

구현 코드 예시
setInterval 같은 함수를 사용해 클라이언트가 정해진 간격으로 서버에 HTTP 요청을 반복해서 보낸다.

setInterval(async () => {
  const res = await fetch('/api/status');
  const data = await res.json();
  setState(data);
}, 5000); // 5초마다 요청

✔️ 장점

  • 구현이 매우 간단하다
  • HTTP 기반이라 어떤 서버 환경이든 쉽게 적용 가능

✔️ 단점

  • 데이터 변경이 없어도 계속 요청을 보내므로 네트워크 낭비 발생
  • 클라이언트 수가 많아질수록 서버 부하 증가
  • 주기 사이에 발생한 변경은 즉시 반영되지 않아 실시간성이 떨어짐

2. Long Polling

Polling의 단점을 보완한 방식
클라이언트가 요청을 보내면 서버는 변경 사항이 생길 때까지 응답을 보류하다가(연결은 유지), 변경이 발생하면 그때 응답한다

✔️ 동작 방식

클라이언트 → 서버: 새 데이터 있나요?
서버: 기다리는 중...
서버 → 클라이언트: 있음!
클라이언트 → 서버: 새 데이터 있나요?
서버: 기다리는 중...

구현 코드 예시

async function longPoll() {
  const response = await fetch('/api/updates?timeout=30000'); // 서버가 변경 시까지 응답 대기
  const data = await response.json();
  handleUpdates(data);
  longPoll(); // 응답 받으면 즉시 다음 요청
}

✔️ 장점

  • Polling보다 실시간성이 높고 불필요한 응답이 줄어든다

✔️ 단점

  • 연결 유지 비용이 발생하고 타임아웃 처리가 필요
  • 메시지가 많아지면 오히려 더 복잡해짐

3. SSE

Server Sent Events
서버에서 클라이언트로만 데이터를 전송하는 단방향 통신 방식
브라우저에 내장된 EventSource API를 통해 클라이언트가 서버의 이벤트를 구독하면, 서버는 연결을 유지한 채 필요한 시점에 이벤트를 지속적으로 전송해준다

✔️ 동작 방식

브라우저에 내장된 EventSource을 이용하여 클라이언트가 서버의 이벤트를 구독한다는 요청을 보냄

클라이언트 → 서버: 연결 요청 (Accept: text/event-stream)
서버 → 클라이언트: 연결 유지... (Content-Type: text/event-stream)
서버 → 클라이언트: data: {"message": "새 알림"}
서버 → 클라이언트: data: {"message": "또 다른 알림"}
(연결 유지 중...)

구현 코드 예시

const es = new EventSource('/api/stream');

es.onmessage = (e) => {
  const data = JSON.parse(e.data);
  setState(data);
};

// 커스텀 이벤트 타입 구분
es.addEventListener('alert', (e) => {
  triggerAlarm(JSON.parse(e.data));
});

es.addEventListener('status', (e) => {
  updateStatus(JSON.parse(e.data));
});

SSE 프로토콜 형식

event: notification 							 // 이벤트 타입
data: {"title": "새 메시지", "body": "안녕하세요"} // 데이터
id: 12345 										// 이벤트 ID
retry: 3000 									// 재연결 대기 시간(ms)

✔️ 장점

  • WebSocket보다 가볍고 구현이 간단
  • 인프라 호환성: HTTP 기반이라 기존 로드밸런서, 프록시 그대로 활용 가능
  • 자동 재연결 기능 내장

✔️ 단점

  • 단방향 통신만 지원
  • HTTP/1.1 환경에서는 브라우저당 도메인 연결 수 제한(6개) 존재

4. WebSocket

최초 HTTP 핸드셰이크 이후 지속 연결을 유지하며 서버와 클라이언트가 양방향으로 데이터를 주고받는 방식

✔️ 동작 방식

클라이언트 → 서버: HTTP 업그레이드 요청
서버 → 클라이언트: 101 Switching Protocols
(이제부터 WebSocket 프로토콜)
클라이언트 ↔ 서버: 양방향 메시지 교환

101 Switching Protocol
클라이언트가 보낸 Upgrade 요청 헤더에 대한 응답이 들어가며 서버에서 프로토콜을 변경할 것임을 알려주는 상태 코드
해당 코드는 Websocket 프로토콜 전환 시에 사용된다

구현 코드 예시

const ws = new WebSocket('wss://example.com/ws');

// 수신
ws.onmessage = (e) => {
  const data = JSON.parse(e.data);
  setState(data);
};

// 송신
ws.send(JSON.stringify({ type: 'subscribe', id: 'room_01' }));

✔️ 장점

  • 양방향 통신
  • 낮은 지연시간

✔️ 단점

  • 구현 복잡도 높음
  • 재연결을 직접 구현해야 함
  • 연결 이후에는 HTTP가 아닌 WebSocket 프로토콜로 동작하므로 별도 인프라 설정 필요 (로드밸런서, 프록시)

🔎 Socket.IO

WebSocket을 기반으로 한 라이브러리
WebSocket의 복잡한 구현을 쉽게 도와주는 라이브러리라고 보면 된다
일단 WebSocket 연결을 시도하고 불가능한 브라우저 환경이라면 자동으로 Long Polling 방식으로 연결한다
자동 재연결, 이벤트 기반 API 등의 편의 기능을 제공한다
구현이 편리하지만 라이브러리 의존성이 생기고 순수 WebSocket보다 약간 느리다.

const socket = io('https://example.com');

// 수신 (on)
socket.on('message', (data) => {
  updateChat(data);
});

// 송신 (emit)
socket.emit('send', { text: '안녕하세요' });


선택 기준

실시간 통신 기술 선택 기준
단방향이면 SSE, 양방향이 필요하면 WebSocket이 기본 기준


🔎 Debounce와 Throttle

실시간 서비스에서는 이벤트가 매우 빠르게 연속으로 발생하게 되는데, 이를 그대로 처리하면 불필요한 API 호출과 렌더링이 과도하게 늘어날 수도 있다
따라서 이를 제어하고 성능을 높이기 위해 Debounce나 Throttle를 고려해볼 수 있음

Debounce

이벤트가 발생할 때마다 기존 타이머를 초기화하며, 호출이 멈춘 후 지정한 시간이 지나면 마지막 이벤트를 기준으로 함수를 실행
즉, 순차적 호출을 하나의 그룹으로 묶어서 처리하는 느낌

불필요한 중간 요청을 제거할 수 있음
단, 실행이 지연되므로 연속 스트림에는 부적합

  • 입력이 끝난 후 한번만 처리하면 되는 경우에 적합 (검색창, 필터 입력 등)
  • 키워드 검색 혹은 자동완성 기능에서 api 함수 호출 횟수를 최대한 줄이고 싶을때

Throttle

스로틀링은 출력을 조절한다는 의미로 이벤트를 일정 시간 간격으로 최대 한 번만 실행되도록 제한

예를 들어 소켓 설정하면서 Throttle 의 설정시간으로 100ms 를 주게되면
소켓 메시지가 10ms마다 와도 실제 차트 업데이트는 100ms에 한 번만 발생

따라서, 실시간 데이터에서 렌더링 빈도를 제어하여 성능을 높일 수 있다
단 중간 데이터는 무시될 수도 있음

계속 오는 데이터의 처리빈도를 제한하여 성능을 올릴 때 적합 (실시간 차트, 소켓 메시지, 스크롤 이벤트 등)

비교해보기

이벤트 발생:  ─▲──▲─▲──▲▲▲──▲──▲─▲─▲──▲

Debounce:    ────────────────────────────▲
             (마지막 이벤트 후 delay 지나면 실행)

Throttle:    ─▲────────▲────────▲────────▲
             (일정 간격으로 한 번씩만 실행)


출처

[Network] 실시간 통신 기술 (폴링, 롱폴링, 웹소켓, SSE)
실시간 통신 기술 비교 (Polling, Webhook, SSE, WebSocket)
백엔드 통신 패턴 총정리 — Short Polling, Long Polling, SSE, Pub/Sub
SSE, Polling, WebSocket 비교 학습 노트
실시간 통신 기술 비교하기 / SSE 알림 기능 구현하기
Debounce 와 throttle 은 뭐고 각각 언제 사용할까?
디바운스(Debounce)와 스로틀(Throttle ) 그리고 차이점
Debounce와 Throttle: 직접 실행하며 알아보기

0개의 댓글