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