WebSocket
WebSocket은 HTTP 업그레이드 핸드셰이크로 시작해, 하나의 TCP 연결 위에서 클라이언트와 서버가 동시에 메시지를 주고받을 수 있는 전이중(full-duplex) 통신 프로토콜입니다. 채팅, 실시간 알림, 주식 시세, 협업 편집처럼 서버가 먼저 데이터를 보내야 하는 장면에서 HTTP의 요청-응답 모델이 가진 한계를 해결합니다.
▶아키텍처 다이어그램
🔄 프로세스 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
HTTP는 클라이언트가 요청하면 서버가 응답하는 구조입니다. 서버에 새로운 데이터가 생겼어도 클라이언트가 물어보지 않으면 보낼 방법이 없습니다. 채팅 메시지가 도착했거나, 주식 가격이 바뀌었거나, 다른 사용자가 문서를 수정한 걸 알리려면 클라이언트가 서버에 계속 '새 데이터 있어?'라고 물어봐야 합니다. 이 폴링 방식은 새 데이터가 없어도 요청이 반복되어 서버 부하와 대역폭을 낭비하고, 폴링 간격만큼 실시간성도 떨어집니다. HTTP Long Polling이나 Server-Sent Events 같은 우회책도 있지만, Long Polling은 연결을 열었다 닫았다 반복하는 오버헤드가 남아 있고 SSE는 서버에서 클라이언트로의 단방향만 지원합니다. 결국 하나의 연결 위에서 양쪽이 자유롭게 보낼 수 있는 방식이 필요해졌고, WebSocket이 그 답입니다.
웹이 문서를 보여주는 매체에서 실시간 인터랙션이 필요한 애플리케이션 플랫폼으로 바뀌면서, HTTP의 요청-응답 모델은 점점 더 자주 벽에 부딪혔습니다. Ajax 폴링으로 실시간 느낌을 흉내 냈지만 사용자가 늘수록 불필요한 요청이 쌓였고, Long Polling은 즉시성을 조금 높였을 뿐 연결 재수립 비용은 그대로였습니다. Comet 같은 기법은 브라우저마다 동작이 달라 호환성 문제가 컸습니다. HTTP 인프라와 호환을 유지하면서도 양방향 전이중 통신을 표준화할 프로토콜이 필요해진 이유입니다. 2011년 RFC 6455로 표준화된 WebSocket은 HTTP 업그레이드로 시작하는 설계 덕분에 기존 웹 서버, 프록시, 방화벽과의 호환성을 확보하며 빠르게 채택됐습니다.
WebSocket 연결은 일반 HTTP 요청으로 시작합니다. 클라이언트가 `Upgrade: websocket` 헤더를 포함한 요청을 보내고, 서버가 `101 Switching Protocols`로 응답하면 그 시점부터 같은 TCP 연결이 WebSocket 프로토콜로 전환됩니다. 이후로는 HTTP의 요청-응답 구조가 사라지고, 양쪽이 언제든 상대에게 메시지 프레임을 보낼 수 있는 전이중 채널이 됩니다. WebSocket 프레임 헤더는 2~14바이트로 HTTP 헤더에 비해 훨씬 작습니다. 이미 열린 연결 위에서 주고받으므로 매번 연결을 새로 맺는 비용도 없습니다. 텍스트 프레임과 바이너리 프레임을 구분할 수 있고, Ping/Pong 프레임으로 연결이 살아 있는지 확인합니다. 연결을 끊을 때는 Close 프레임을 교환해 양쪽이 정리할 시간을 갖습니다. 이 구조 덕분에 서버가 이벤트 발생 즉시 클라이언트에 푸시할 수 있고, 클라이언트도 별도 요청 없이 서버에 메시지를 보낼 수 있습니다.
WebSocket과 HTTP는 둘 다 TCP 위의 애플리케이션 계층 프로토콜이고, WebSocket 연결 자체가 HTTP 핸드셰이크로 시작합니다. 하지만 통신 패턴이 근본적으로 다릅니다. HTTP는 클라이언트가 요청해야만 서버가 응답하는 반이중 구조입니다. 서버가 먼저 데이터를 보내려면 클라이언트의 요청을 기다리거나 우회 기법이 필요합니다. WebSocket은 한 번 연결되면 양쪽이 독립적으로 메시지를 보낼 수 있습니다. Server-Sent Events(SSE)도 서버 푸시를 지원하지만 서버에서 클라이언트로의 단방향이며, HTTP 위에서 동작해 프로토콜 전환 없이 쓸 수 있습니다. 서버 푸시만 있으면 되고 클라이언트가 응답할 필요가 없다면 SSE가 더 단순한 선택입니다. 양방향 실시간 메시지 교환이 필요하면 WebSocket이 맞고, 전통적인 요청-응답이면 HTTP로 충분합니다. WebSocket은 만능이 아닙니다. 연결 상태를 유지하므로 서버 메모리를 점유하고, 수십만 동시 연결이면 자원 관리가 별도의 설계 문제가 됩니다.
WebSocket은 채팅, 실시간 알림, 라이브 대시보드, 협업 편집, 멀티플레이어 게임처럼 서버와 클라이언트가 연결을 유지한 채 양방향으로 빈번하게 메시지를 주고받아야 하는 장면에서 가장 자연스러운 선택입니다. 서버 이벤트가 불규칙하게 발생하고 지연이 수십 밀리초 이내여야 할 때, 폴링으로는 충족하기 어려운 요구를 직접 해결합니다. 반면 서버가 가끔 데이터를 보내기만 하고 클라이언트 응답이 필요 없다면 SSE가 더 단순합니다. 일반 API 호출처럼 요청-응답 한 번이면 충분한 통신에 WebSocket을 쓰면 연결 유지 비용만 늘어납니다. 배포 시에는 앞단 프록시나 로드 밸런서가 WebSocket 업그레이드를 올바르게 처리하는지, 긴 연결을 중간에 끊지 않는지도 사전에 확인해야 합니다.