들어가며
최근, 저희 회사에서는 새로운 채팅 서비스 개발에 착수했습니다. 이 과정은 기존에 존재하던 백엔드의 웹소켓 기반 레거시 코드를 재사용하려는 초기 시도에서 시작되었습니다. 하지만 프로젝트 진행 중, 몇 가지 도전과제를 마주하게 되었고, 이는 저희 팀이 아예 제로베이스에서 시작하는 결정을 내리는 계기가 되었습니다.
이러한 전환점에서, 실시간 웹 통신 방법에 대해 재고찰하게 되었고, 최종적으로 서버-전송 이벤트(Server-Sent Events, SSE)를 채택하기로 결정했습니다. 그리고 공부하는김에 익숙한 4가지 실시간 웹 통신에대해 포스팅 하려고 합니다.
Polling
폴링은 실시간 웹 통신에서 가장 기본적인 방법 중 하나로, 클라이언트가 주기적으로 서버에 HTTP 요청을 보내어 새로운 정보가 있는지 확인하는 방식입니다. 이러한 방식은 간단하고 직관적이며, 많은 전통적인 웹 애플리케이션에서 사용되어 왔습니다.
폴링은 간단한 실시간 애플리케이션 또는 데이터 변경 빈도가 낮은 경우에 적합한 방식입니다. 하지만 높은 서버 부하와 데이터 지연으로 인해 실시간 반응이 중요한 고성능 애플리케이션에는 다른 방법을 고려하는 것이 좋습니다.
장점:
- 간단한 구현: 폴링은 다른 실시간 통신 방법에 비해 구현하기 쉬워, 개발자가 빠르게 도입할 수 있습니다.
- 광범위한 호환성: 거의 모든 웹 브라우저와 서버 환경에서 지원되므로, 넓은 호환성을 가지고 있습니다.
- 상태가 없는 서버에 적합: 각 요청이 독립적이므로, 상태를 유지하지 않는 서버 환경에 적합합니다.
단점:
- 서버 부하: 클라이언트가 정기적으로 요청을 보내기 때문에, 서버에 지속적인 부하가 발생할 수 있습니다.
- 데이터 지연: 새로운 데이터가 생성된 후 클라이언트가 다음 폴링 요청을 보낼 때까지 지연이 발생할 수 있습니다. 이는 실시간성이 중요한 애플리케이션에는 적합하지 않을 수 있습니다.
- 효율성 문제: 서버에 변경사항이 없어도 요청이 지속적으로 이루어지므로, 네트워크 트래픽과 서버 자원을 비효율적으로 사용할 수 있습니다.
Long Polling
롱 폴링은 실시간 웹 통신에서 폴링의 한계를 극복하기 위해 개발된 방법입니다. 클라이언트가 서버에 요청을 보내면 서버는 새로운 데이터가 준비될 때까지 요청을 보류합니다. 데이터가 준비되면 서버는 해당 데이터와 함께 응답을 보내고 클라이언트는 즉시 다음 요청을 보내어 이 과정을 반복합니다.
롱 폴링은 폴링의 단점을 개선하고, 웹소켓이나 SSE를 사용하기 어려운 환경에서 실시간 통신을 구현할 수 있는 유용한 대안입니다. 데이터의 실시간성이 중요하지만, 복잡한 기술 스택을 피하고 싶은 경우에 적합한 방식입니다.
장점:
- 효율적인 데이터 전송: 새로운 데이터가 생길 때만 서버가 응답을 보내기 때문에, 네트워크 트래픽과 서버 부하가 폴링에 비해 상대적으로 낮습니다.
- 실시간성 개선: 새로운 데이터가 있을 때 즉시 클라이언트에 전달되므로, 폴링에 비해 데이터의 실시간성이 향상됩니다.
- 간단한 구현: 웹소켓이나 SSE에 비해 구현이 비교적 간단하며, 기존의 HTTP 인프라를 활용할 수 있습니다.
단점:
- 연결 지연: 서버가 새로운 데이터를 기다리는 동안 클라이언트의 요청은 계속 대기 상태에 있게 됩니다. 이는 서버 자원을 오래 점유할 수 있습니다.
- 스케일링 문제: 대규모 동시 연결을 처리하는 데에는 한계가 있으며, 많은 수의 클라이언트가 동시에 접속하는 환경에서는 서버 부하가 커질 수 있습니다.
- 복잡한 클라이언트 로직: 클라이언트는 서버 응답 후 즉시 새로운 요청을 보내야 하므로, 클라이언트 측에서의 요청 관리가 복잡해질 수 있습니다.
웹소켓 (WebSocket)
웹소켓은 양방향, 지속적인 연결을 통해 실시간 웹 통신을 가능하게 하는 고급 기술입니다. 한 번의 핸드셰이크로 연결이 이루어진 후, 클라이언트와 서버 간에 실시간 데이터 교환이 가능해집니다.
웹소켓은 실시간 채팅, 온라인 게임, 금융 시장 데이터 스트리밍 등 양방향 통신이 필수적인 고급 애플리케이션에 적합합니다.
장점:
- 양방향 실시간 통신: 클라이언트와 서버가 언제든지 데이터를 주고받을 수 있어, 실시간 인터랙션이 필요한 애플리케이션에 이상적입니다.
- 낮은 지연 시간: 연결이 지속되므로 데이터 교환에 소요되는 시간이 짧습니다. 이는 빠른 사용자 경험을 제공합니다.
- 효율적인 네트워크 사용: 핸드셰이크 후에는 오버헤드 없이 데이터를 전송할 수 있어, 네트워크 자원을 효율적으로 사용합니다.
단점:
- 보안 고려사항: 웹소켓은 추가적인 보안 조치가 필요할 수 있습니다.
- 브라우저 및 서버 호환성: 모든 브라우저와 서버 환경에서 지원되지 않을 수 있습니다.
- 복잡한 백엔드 로직: 연결 관리, 메시지 처리 등 복잡한 백엔드 로직을 구현해야 합니다.
서버-전송 이벤트 (Server-Sent Events, SSE)
서버-전송 이벤트(SSE)는 서버에서 클라이언트로 단방향 데이터를 지속적으로 스트리밍하는 데 사용되는 기술입니다. 클라이언트는 초기 연결을 설정한 후, 서버로부터 데이터를 지속적으로 받습니다.
SSE는 실시간 뉴스 피드, 주식 시세 업데이트, 로그 스트리밍 등 서버에서 클라이언트로 지속적인 정보를 제공해야 하는 경우에 적합합니다.
장점:
- 단방향 지속적 데이터 스트리밍: 서버에서 클라이언트로 지속적으로 데이터를 보낼 수 있어, 실시간 정보 업데이트에 이상적입니다.
- 간단한 클라이언트 구현: SSE 클라이언트 구현은 웹소켓에 비해 간단하며, 기본적으로 HTTP를 사용합니다.
- 자동 재연결: 연결이 끊어진 경우 자동으로 재연결을 시도합니다.
단점:
- 단방향 통신: 클라이언트에서 서버로 데이터를 보낼 수 없습니다.
- 지원 문제: 일부 브라우저에서는 SSE를 지원하지 않을 수 있습니다.
- 하드웨어 리소스 사용: 서버가 많은 수의 연결을 지속적으로 유지해야 하므로, 서버 리소스 사용이 증가할 수 있습니다.
SSE 통신 과정
- 클라이언트의 초기 요청: 클라이언트는 서버에 HTTP GET 요청을 보냅니다. 이 요청은 서버로부터 데이터를 받기 위한 연결을 초기화합니다. 클라이언트는 이 요청을 통해 SSE 연결을 시작하려는 의도를 나타냅니다.
- 서버의 응답 및 연결 설정: 서버는 이 요청을 받고 클라이언트에 text/event-stream 형식의 MIME 타입으로 응답합니다. 이 응답은 연결이 성공적으로 설정되었음을 나타내며, 서버는 이 연결을 열어 두고 지속적으로 데이터를 전송할 수 있습니다.
- 데이터 전송: 연결이 설정된 후, 서버는 클라이언트로 데이터를 스트리밍합니다. 데이터는 일반적으로 "이벤트 스트림" 형식으로 전송되며, 각 데이터 조각은 data: 필드로 시작합니다. 서버는 새로운 데이터가 있을 때마다 이를 클라이언트로 보내며, 각 메시지는 개행 문자로 구분됩니다.
- 자동 재연결: 클라이언트와 서버 간의 연결이 끊어지면, 클라이언트는 자동으로 서버에 재연결을 시도합니다. 대부분의 브라우저는 이 재연결 메커니즘을 내장하고 있어, 네트워크 중단이나 서버 장애 후에도 연결을 자동으로 복구할 수 있습니다.
- 클라이언트의 연결 종료: 클라이언트가 더 이상 데이터를 받지 않기를 원할 경우, 연결을 명시적으로 닫을 수 있습니다. 일반적으로 이는 클라이언트 측의 스크립트를 통해 수행됩니다.
마치며
오늘의 포스팅에서는 폴링, 롱 폴링, 웹소켓, 그리고 SSE와 같은 실시간 웹 통신 기술들을 살펴보았습니다. 각 기술은 그 자체의 장단점을 가지며, 특정 상황과 요구사항에 따라 적합한 선택이 달라질 수 있습니다.
폴링과 롱 폴링은 간단한 실시간 데이터 전송에 적합하지만, 고성능이 요구되는 상황에서는 그 한계를 드러낼 수 있습니다. 반면, 웹소켓은 실시간 양방향 통신에 최적화되어 있으며, SSE는 서버로부터 클라이언트로의 지속적인 데이터 스트리밍에 효율적입니다!
실시간 웹 애플리케이션을 개발할 때, 이러한 다양한 옵션들을 고려하여 최적의 사용자 경험을 제공할 수 있는 방법을 선택하는 것이 중요합니다. 오늘 공유한 정보가 여러분의 프로젝트에 조금이나마 도움이 되기를 바랍니다. 감삼다.