콘텐츠로 바로가기

WebSocket & Real-time Communication

HTTP의 단방향 소통 한계를 넘어 서버와 클라이언트 간의 물리적 양방향 소통을 가능케 하는 WebSocket 규약과 실시간 스트리밍 제어 물리학을 다루는 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

network-communicationnetworkcommunicationweb-protocolsapi-paradigmsweb-socketreal-time-communicationapplication-protocols10 min read

1. Overview

웹소켓과 실시간 통신(WebSocket & Real-time Communication)은 "클라이언트가 물어봐야만 서버가 대답한다"는 HTTP의 고전적 철학을 박살 내고, 서버가 원할 때 언제든 클라이언트에게 데이터를 꽂아버리는 서버 주도형(Server-Push) 양방향 스트리밍 기술을 해부합니다.

학습자는 채팅이나 주식 호가창을 만들기 위해 서버를 미친 듯이 찔러대던 원시적인 **폴링(Polling)**과 멱살을 잡고 기다리는 **롱 폴링(Long Polling)**의 서버 과부하 참사를 뜯어봅니다. 나아가 HTTP의 껍데기를 쓰고 연결을 맺은 뒤 곧바로 순수한 양방향 TCP 터널로 탈바꿈(Upgrade)하는 **웹소켓(WebSocket)**의 마법을 장악합니다. 마지막으로, 양방향 통신이 필요 없고 오직 서버에서 클라이언트로 일방적인 스트리밍만 필요할 때 HTTP의 표준 규약 안에서 가장 우아하게 동작하는 **SSE(Server-Sent Events)**의 실용적 설계 역량을 확보합니다.

2. Scope & Boundaries

In-Scope

  • HTTP 한계 극복 기법: Short Polling, Long Polling, Streaming.
  • WebSocket Protocol: HTTP Upgrade Header, ws:// vs wss://, 양방향(Full-Duplex) 이진 프레이밍.
  • SSE (Server-Sent Events): 단방향(Server-to-Client) 통신, text/event-stream, 자동 재접속(Auto-reconnect).
  • Pub/Sub 아키텍처 연동: 웹소켓 서버 여러 대를 Redis Pub/Sub으로 묶어 브로드캐스팅하는 인프라 구조.

Out-of-Scope

  • WebRTC P2P 스트리밍: 클라이언트(브라우저) 간의 직접 통신과 미디어 코덱 \rightarrow 08-02-04 UDP & Real-time 영역으로 분리.
  • STOMP / MQTT: 웹소켓 위에서 동작하는 메시징 서브 프로토콜의 구체적 패킷 포맷 \rightarrow 05. Distributed Messaging 영역으로 위임.

Boundaries

  • WebSocket vs SSE: 웹소켓은 "유저와 유저가 서로 타자를 치는" 카카오톡 같은 실시간 양방향(Bidirectional) 채팅에 씁니다. 반면 SSE는 "서버가 수만 명의 유저에게 동시에 알림이나 주식 가격을 쏴주는" 일방향(Unidirectional) 푸시에 씁니다. 양방향이 무조건 좋은 것이 아니며, 무거운 웹소켓 대신 가볍고 방화벽을 쉽게 뚫는 SSE를 선택해야 하는 비즈니스적 경계(예: ChatGPT의 응답 스트리밍)를 명확히 긋습니다.

3. Counterexample

  • 폴링(Polling) 디도스(DDoS) 자폭: 주식 호가창을 만든 프론트엔드 개발자가 최신 가격을 보여주려고 setInterval을 써서 1초마다 백엔드에 API 요청(Short Polling)을 날렸습니다. 동시 접속자가 10,000명이 되자 1초에 10,000번의 HTTP 요청과 DB 쿼리가 터졌습니다. 진짜 트래픽(가격 변동)은 10초에 한 번 발생하는데, 90%의 빈 요청(Empty Response) 때문에 회사의 웹 서버와 DB가 스스로 뻗어버린 끔찍한 자폭입니다.
  • 로드밸런서와 웹소켓의 단절: 웹소켓으로 채팅 서버 3대(A, B, C)를 띄웠습니다. 유저 1은 로드밸런서를 통해 서버 A에 붙고, 유저 2는 서버 B에 붙었습니다. 유저 1이 채팅을 치면 서버 A 메모리에만 기록되므로, 서버 B에 붙은 유저 2는 그 채팅을 볼 수 없습니다. 백엔드 서버가 늘어날 때 웹소켓 세션이 서버 메모리에 묶여버리는 Stateful의 한계를 파악하지 못해, Redis Pub/Sub 같은 백플레인(Backplane)을 설계하지 않은 아키텍처 재앙입니다.

4. Prerequisites

  • HTTP Stateless 철학 (Basic): HTTP 통신의 단발성. (08-04-01 HTTP Evolution)
  • Pub/Sub 패턴 (Basic): 메시지 브로드캐스팅의 개념. (07-06-02 Event-Driven Architecture)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 The Illusion of Real-time (Polling) 서버가 먼저 말을 걸 수 없다는 HTTP의 치명적 한계를 회피하기 위해, 미친 듯이 질문을 던지며 서버를 학대하던 구시대적 꼼수들을 쥡니다. P1
2 WebSocket Upgrade Magic HTTP로 조신하게 인사(Handshake)를 나눈 뒤, 갑자기 "우리 선 넘자!"라며 양방향 TCP 터널로 프로토콜을 탈바꿈하는 해킹적 마법을 해부합니다. P5
3 SSE (Server-Sent Events) 무거운 웹소켓 대신, HTTP 연결을 끊지 않고 텍스트 스트림을 통해 서버가 일방적으로 알림을 쏟아내는 실용적 푸시(Push) 기술을 뜯어봅니다. Industry
4 Scaling Real-time Servers 웹소켓을 맺은 유저들이 서로 다른 백엔드 서버에 찢어져 있을 때, Redis Pub/Sub을 통해 채팅 메시지를 전체 서버로 전파하는 확장판을 장악합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 실시간의 환상, 폴링과 롱 폴링 (The Illusion of Real-time)

  • Why to Learn: 진정한 실시간 기술(WebSocket)이 발명되기 전, 개발자들이 HTTP의 Stateless/단발성 한계를 극복하기 위해 서버 리소스를 쥐어짜던 안티 패턴과 그 한계를 통찰하기 위함입니다.
  • What to Learn:
    • Concepts: Short Polling, Long Polling, HTTP Request Overhead, Empty Response.
    • Skills: 크롬 개발자 도구로 주식 사이트의 Network 탭을 열어, 데이터 변경이 없는데도 200 OK 빈 껍데기 응답만 낭비하는 Short Polling 트래픽 관찰하기.
  • How to Learn:
    • 1단계: Short Polling (단순 무식): "새 메시지 왔어?" "아니." "지금은?" "아니." 이걸 1초마다 반복합니다. 서버가 터집니다.
    • 2단계: Long Polling (멱살 잡기): 클라이언트가 "새 메시지 왔어?"라고 묻습니다. 서버는 메시지가 없으면 대답하지 않고 연결을 물고 늘어집니다(예: 30초 대기). 10초 뒤에 메시지가 생기면 그제야 "응, 왔어!" 하고 대답하며 연결을 끊습니다. 클라이언트는 응답을 받자마자 다시 멱살을 잡으러 요청을 보냅니다. 빈 요청은 줄었지만, 여전히 HTTP 헤더를 계속 주고받아야 하는 무거움의 딜레마를 해부합니다.
  • Implement: 파이썬 Long Polling 서버 시뮬레이터. 클라이언트가 /poll 요청. 서버는 while True:를 돌며 1초마다 DB 검사 (time.sleep(1)). 5초 뒤 타 서버에서 DB에 새 데이터 Insert \rightarrow 루프가 변경 감지하고 HTTP 200 OK 뱉음. 만약 30초간 변화 없으면 HTTP 204 No Content(타임아웃) 뱉는 로직 렌더링.

Core Topic 02: 선을 넘는 HTTP, 웹소켓 (WebSocket Upgrade Magic)

  • Why to Learn: HTTP의 단발성을 완전히 버리고, 최초 1회의 핸드셰이크만으로 영구적인 양방향 이진 통신(TCP) 터널을 뚫어내는 진정한 실시간 게임/채팅의 뼈대를 장악하기 위함입니다.
  • What to Learn:
    • Concepts: WebSocket Protocol (ws://, wss://), HTTP Upgrade Header (Connection: Upgrade), Full-Duplex (양방향 전이중), Binary Framing.
    • Skills: 웹소켓 핸드셰이크 요청의 Sec-WebSocket-Key와 서버의 Sec-WebSocket-Accept 암호화 응답을 통한 터널 뚫기 검증 로직 이해.
  • How to Learn:
    • 1단계: 합법적인 프로토콜 이탈 (Upgrade): 웹소켓은 포트를 새로 뚫지 않습니다(기존 80, 443 사용). 방화벽을 우회하기 위해 HTTP로 위장합니다. GET /chat HTTP/1.1을 보내면서 헤더에 Upgrade: websocket을 쓱 끼워 넣습니다.
    • 2단계: 서버의 화답과 터널 개통: 서버가 이 헤더를 보고 HTTP 101 Switching Protocols 상태 코드를 던집니다. "좋아, 지금부터 우리는 HTTP가 아니라 TCP야!" 이 순간부터 무거운 HTTP 헤더는 완전히 사라지고, 수 바이트짜리 초경량 이진 프레임(Binary Frame)만 탁구공처럼 미친 속도로 오고 가는 양방향(Full-Duplex) 마법을 뜯어봅니다.
  • Implement: WebSocket Upgrade 스니퍼 시뮬레이션. 클라이언트 송신: Connection: Upgrade, Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==. 서버 수신 로직: 해당 Key에 258EAFA5-E914... 매직 스트링을 붙인 후 SHA-1 해싱 및 Base64 인코딩. 서버 응답: HTTP/1.1 101 Switching Protocols, Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=. 이 암호학적 화답이 맞아야만 브라우저가 소켓을 뚫어주는 보안 규약 렌더링.

Practical

Core Topic 03: 가볍고 우아한 단방향 스트리밍, SSE (Server-Sent Events)

  • Why to Learn: 양방향 채팅이 아니라 단순히 서버의 알림(Notification)이나 ChatGPT의 타자 치는 효과를 구현할 때, 무거운 웹소켓 대신 HTTP의 기본 스펙만으로 구현 가능한 우아한 푸시 기술을 쥐기 위함입니다.
  • What to Learn:
    • Concepts: SSE (Server-Sent Events), text/event-stream, Unidirectional (단방향), EventSource API, Auto-reconnect.
    • Skills: 클라이언트가 EventSource 객체로 연결을 열고, 서버가 연결을 끊지 않은 채 data: 메세지\n\n 포맷으로 텍스트를 계속 밀어내는(Flush) ChatGPT 스트리밍 API 짜기.
  • How to Learn:
    • 1단계: 웹소켓의 오버스펙: 서버에서 클라이언트로 일방적으로 뉴스 속보나 주식 가격만 쏴주면 되는데, 굳이 웹소켓이라는 무거운 이중 터널을 뚫는 건 인프라적 낭비입니다.
    • 2단계: HTTP 스트리밍 (SSE): 클라이언트가 일반 HTTP 요청을 보냅니다. 서버는 응답 헤더에 Content-Type: text/event-stream을 적습니다. 그리고 연결을 안 끊습니다! 서버는 이벤트가 생길 때마다 바디(Body)에 텍스트를 한 줄씩 밀어 넣습니다(Flush). 브라우저는 이 텍스트가 들어올 때마다 자바스크립트 이벤트를 빵빵 터뜨려 화면을 그립니다. 심지어 끊어지면 브라우저가 '알아서 재접속'까지 해주는 SSE의 극강의 실용성을 해부합니다.
  • Implement: ChatGPT 텍스트 스트리밍 모사 (Node.js/Python). 응답 헤더 설정 Transfer-Encoding: chunked. 서버 루프: ["Hello", " I am", " Antigravity", "."] 배열을 0.5초 간격으로 순회하며 res.write('data: ' + word + '\n\n') 호출. 클라이언트 렌더링 측에서 한 글자씩 타이핑되는 효과를 연출하며, 단일 HTTP 연결이 2초간 열려있는 타임라인 렌더링.

Advanced

Core Topic 04: 웹소켓 서버의 한계와 스케일 아웃 (Scaling Real-time Servers)

  • Why to Learn: 웹소켓은 상태(세션)를 메모리에 물고 있기 때문에, 서버가 1대에서 3대로 늘어나는 순간 서버 간의 단절로 인해 채팅방이 쪼개지는 최악의 인프라 병목을 박살 내기 위함입니다.
  • What to Learn:
    • Concepts: Stateful Connection, Load Balancing Sticky Session, Pub/Sub Architecture, Redis Pub/Sub, Backplane.
    • Skills: 3대의 Node.js 웹소켓 서버 뒤에 Redis를 배치하여, 유저 1(서버 A)이 보낸 메시지를 유저 2(서버 B)가 받아볼 수 있게 백플레인(Backplane) 파이프라인 설계.
  • How to Learn:
    • 1단계: 고립된 섬 (Stateful의 저주): 유저 1만 명이 접속해 서버 10대를 띄웠습니다. 유저 A는 1번 서버에, 유저 B는 2번 서버에 소켓이 꽂혔습니다. A가 "안녕" 치면 1번 서버 메모리에만 들어갑니다. 2번 서버에 있는 B는 평생 그 메시지를 볼 수 없습니다.
    • 2단계: 백플레인 브로드캐스팅 (Redis): 10대의 서버 뒤에 거대한 사내 방송국(Redis Pub/Sub)을 차립니다. A가 "안녕" 치면, 1번 서버는 이 메시지를 유저에게 뿌리기 전에 먼저 Redis 방송국으로 던집니다(Publish). Redis는 10대의 모든 서버에게 "야, 1번 채팅방에 '안녕' 떴어!"라고 방송(Subscribe)합니다. 그제야 2번 서버가 자기한테 꽂힌 유저 B에게 메시지를 쏴주는, 거대한 분산 실시간 아키텍처를 뜯어봅니다.
  • Implement: 분산 채팅방 아키텍처 스크립트. Server_A (유저 1 연결), Server_B (유저 2 연결). 유저 1이 Server_A[Room1] Hello 전송. Server_A 로직: 자기가 데리고 있는 유저 중 Room1 찾아서 보냄 + Redis.publish('Room1_Channel', 'Hello'). Server_B 로직: Redis 이벤트 수신 \rightarrow 자기가 데리고 있는 유저 2(Room1)에게 Hello 쏴줌. 서버 간 메모리 고립을 끊어내는 글로벌 이벤트 버스 파이프라인 렌더링.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Long Polling (롱 폴링) 클라이언트가 서버에 요청을 보낸 뒤, 서버가 새 데이터가 생길 때까지 응답을 질질 끌며(Hold) 대기하다가 데이터가 발생하면 그제야 응답을 끊어버리는 과도기적 실시간 기법입니다. 기본 유사 실시간 데이터 푸시 Short Polling WebSocket / SSE 연결을 오래 유지하긴 하지만 1번 응답하면 무조건 끊어지므로, 브라우저가 곧바로 다시 요청(재접속)을 때려야 하는 굴레를 벗어나진 못함 P1:CS2023 core
WebSocket (웹소켓) 처음엔 HTTP로 인사(Handshake)한 뒤 101 Switching Protocols 응답을 기점으로 무거운 HTTP 허물을 벗어던지고, 양방향(Full-Duplex) 이진 통신을 영구적으로 유지하는 L7 프로토콜입니다. 권장 완전한 양방향 실시간 통신 HTTP Upgrade Header HTTP / SSE HTTP를 우회하기 위한 꼼수로 포트 80/443을 쓸 뿐, 핸드셰이크 이후에는 HTTP와 완전히 다른 독자적인 패킷(Frame) 포맷으로 동작함 P5:SFIA core
SSE (Server-Sent Events) 웹소켓처럼 양방향이 될 필요 없이, 오직 서버에서 클라이언트로 단방향 알림만 쏴줄 때 HTTP 연결 하나를 열어두고 텍스트 데이터를 계속 흘려보내는(Streaming) 우아한 푸시 기술입니다. 실무 단방향(서버->클라이언트) 스트리밍 text/event-stream / Chunked WebSocket 통신사가 막아버리거나 방화벽이 걸리는 웹소켓과 달리, SSE는 100% 표준 HTTP 기반이라 방화벽 프리패스가 보장됨 Industry core
Redis Pub/Sub (레디스 펍섭) 웹소켓 서버가 로드밸런서 뒤에 10대로 쪼개졌을 때(Scale-out), 한 서버에 들어온 채팅 메시지를 다른 9대의 서버에도 브로드캐스팅해 주는 뒤 단의 거대한 인프라 방송국(Backplane)입니다. 심화 Stateful 서버 간의 메시지 브로드캐스팅 WebSocket Scaling Kafka (메시지 큐) Redis Pub/Sub은 쏘고 잊어버리는(Fire and Forget) 휘발성 방송이므로, 메시지 영속성(보존)이 필요하면 Kafka나 RabbitMQ를 고려해야 함 Industry core

8. References

Primary

  • [P1] CS2023 - Networking and Communication (NC) - Application Layer Protocols (WebSockets)
  • [P5] SFIA - Software Design (SWDN) - Real-time Application Design

Secondary

  • [High Performance Browser Networking] Ilya Grigorik - Server-Sent Events (SSE) and WebSocket
  • [Designing Data-Intensive Applications] Martin Kleppmann - Message Brokers (Pub/Sub)

Industry

  • [IETF RFC 6455] - The WebSocket Protocol
  • [W3C Server-Sent Events API] - EventSource interface
  • [Redis Documentation] - Redis Pub/Sub

9. Final Checklist

Primary

  • 서버에 데이터가 없어도 정해진 주기마다 무의미한 HTTP 요청을 폭격하는 Short Polling과, 서버가 연결을 쥐고 대기하는 Long Polling의 아키텍처적 부하 차이를 비교할 수 있는가?
  • 브라우저가 Connection: Upgrade 헤더를 포함한 HTTP 요청을 보내면, 서버가 101 Switching Protocols 상태 코드로 화답하여 순수 TCP 양방향 채널로 탈바꿈하는 WebSocket 핸드셰이크를 증명할 수 있는가?

Secondary

  • 카카오톡 같은 유저 간 양방향 채팅에는 WebSocket을 쓰고, 주식 거래소의 실시간 가격 브로드캐스팅이나 ChatGPT의 타이핑 응답에는 HTTP 표준인 SSE(text/event-stream)를 써야 하는 비즈니스 트레이드오프를 평가할 수 있는가?
  • 대용량 텍스트나 바이너리 데이터를 웹소켓으로 보낼 때, 브라우저 메모리가 터지는 것을 막기 위해 데이터를 작게 쪼개어(Chunking) 여러 개의 프레임(Frame)으로 전송하고 조립하는 메커니즘을 해부할 수 있는가?

Industry

  • 클라이언트 수만 명이 로드밸런서 뒤의 웹소켓 서버 5대(A, B, C, D, E)에 분산 접속한 상태에서, 서버 A의 유저가 보낸 메시지를 서버 B의 유저에게 전달하기 위한 Redis Pub/Sub (Backplane) 기반의 글로벌 브로드캐스트 파이프라인을 설계할 수 있는가?
  • 백엔드 서버가 무중단 배포(Rolling Update)로 인해 내려갈 때, 물려있던 수만 개의 Stateful 웹소켓 세션이 끊어지는 재접속 폭풍(Connection Storm)을 완화하기 위한 클라이언트 측의 Exponential Backoff(지수 백오프) 재시도 로직을 설계할 수 있는가?

Application Protocols & API Paradigms

3 / 5