Software Engineering

WebSocket, Server-Sent Events(SSE), HTTP Polling

남희정 2024. 12. 14. 16:23

📌 목차

Albert의 메세지

 

알버트가 웹소켓과 SSE, Polling에 대한 질문을 보내왔다. 전부 제대로 대답하지 못할 뿐더러, 실무에서 실시간으로 이미지와 Json을 받을 때 웹 소켓을 사용해보았는데 고려할 수 있는 다른 방식에 대해선 알아본 적이 없다는 것을 깨달았다. 그가 보내준 질문(5번은 제외)과 함께 공부해보는 시간을 가져볼까 한다.

 

Think mainly:

  1. When to pick web socket over the other (sse, polling, etc). Any other options?
    웹소켓(WebSocket)을 다른 방식(SSE, Polling 등) 대신 선택해야 할 때는 언제인가? 다른 선택지는 무엇이 있는가?
  2. The catch when choosing either?
    각각의 방식을 선택했을 때의 장단점은 무엇인가?
  3. How easy it is to pivot if shit hits the fan?
    문제가 생겼을 때 다른 방식으로 전환하기가 얼마나 쉬운가?
  4. Is it doable in a serverless setup?
    서버리스 환경에서 구현이 가능한가?
  5. Your hands on experience with WebSockets? Or just a friend to discuss it openly
    WebSocket을 사용한 실무 경험이 있는가? 아니면 그냥 이런 주제를 편하게 이야기할 친구가 필요한가?

https://tecoble.techcourse.co.kr/post/2022-10-11-server-sent-events/

HTTP Polling

폴링 Polling은 하나의 프로그램이 충돌 회피 또는 동기화 처리 등을 목적으로 다른 프로그램의 상태를 주기적으로 검사하여 한 조건을 만족할 때 송수신 등의 자료처리를 하는 방식을 말한다. 일정한 주기(특정한 시간)를 갖고 서버와 응답을 주고 받는 HTTP 연결의 가장 일반적인 패턴이다. 이렇게 서버와 응답을 주고 받는 이유는 웹이 태생 자체부터 실시간을 위해 필수적인 persistent connection이 불가능하기 때문. (HTTP/1.1은 TCP/IP 연결을 재사용하는 persistent connections(keep-alive 혹은 connection re-use.)를 도입하여 성능을 일부 개선했지만 대부분의 경우 비활성 시간 초과에 따라 최종적으로 닫힌다.)

 

HTTP 프로토콜로 실시간 애플리케이션을 만들기 위해선 2가지의 제약사항이 있다. 

 

✔️ 클라이언트가 연결의 주체이다.

서버는 요청을 기다려야 하고, 서버에서 데이터 변경이 일어나 알려줘야할 때를 고려할 수 없다. 

 

✔️ Stateless 무상태이다.

서버와 클라이언트 간에 연결이 유지되지 않기 때문에 기존의 문맥과 상태를 유지하면서 최소한의 정보만 효과적으로 주고 받기가 어렵다. HTTP 요청/응답 메시지에는 Header가 차지하는 공간이 크기 때문에, 채팅 애플리케이션처럼 짧은 문장의 메세지를 지속적으로 주고 받을 경우 네트워크 대역폭의 낭비가 심해져 배보다 배꼽이 더 커지는 상황이 된다.

 

즉, 폴링의 주기가 짧으면 서버의 성능에 부담이 간다. 정보가 변하지 않을 경우 불필요한 응답이 많아질 것이고 오버헤드가 발생할 수 있다. 또한, 주기가 길면 실시간성이 떨어진다.

 

요청 주기가 일정하지만 넉넉하게 갱신되는 서버 데이터의 경우엔 유용하게 사용할 수 있겠다.

 

https://tecoble.techcourse.co.kr/post/2022-10-11-server-sent-events/

 

Long-Polling이라는, 서버 측에서 접속을 열어두는 시간을 길게하는 방식을 가진 기법도 있다. Polling의 비효율성을 개선하기 위해 등장했다. 이벤트가 발생(변경된 데이터 존재시)하면 바로 응답이 이루어져서 실시간성이 아주 높으며 스트리밍 방식과 달리 웹 브라우저 환경에 관계없이 사용할 수 있다. 데이터가 자주 바뀌는 케이스보다 실시간 메시지 전달이 중요하지만 서버의 상태가 빈번하게 변하지 않는 케이스에 적합하다.  또한 Polling과 Long-Polling의 경우 모두 오래 연결되어 있는 커넥션을 최적화하지 못하는 문제가 있다. 이를 위해선 연결된 커넥션과 요청 리스트를 갖고 있어야 한다. 

 

이를 위한 대안으로 WebSocket이나 Server-Sent Events(SSE)를 사용한다.

 

WebSocket 

https://upload.wikimedia.org/wikipedia/commons/7/72/FullDuplex.JPG

 

웹소켓WebSocket은 하나의 TCP 접속에 전이중 통신(두 지점 사이에서 정보를 주고 받는 전자 통신 시스템)채널을 제공하는 컴퓨터 통신 프로토콜이다. 웹소켓 연결이 되려면 일반 HTTP 통신과 마찬가지로 클라이언트는 서버로 GET 요청을 보내야 한다. 이때, Connection과 Upgrade와 같이 웹소켓에서만 쓰이는 Header를 함께 보낸다. 서버에서 101 Switching Protocols 상태 코드를 응답해주면 그때부터 양방향으로 메시지를 주고 받을 수 있게 된다.

 

GET /chat HTTP/1.1
Host: www.test.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

 

https://sendbird.com/developer/tutorials/websocket-vs-http-communication-protocols

 

 

✔️ 양방향 통신 Bidirectional communication

클라이언트와 서버 모두 오랫동안 persistent connection을 통해 동시에 데이터를 보내고 받을 수 있다. 이런 유형의 통신은 *HTTP 폴링보다 오버헤드가 적기 때문에 애플리케이션에 실시간 기능에 대한 여러 이점을 제공한다.

 

✔️ 기존 HTTP 포트와 호환 (80, 443)

최초 접속이 일반 HTTP Request => handshaking 과정을 통해 이루어지기 때문에 기존의 80, 443 port로 접속한다. 추가로 방화벽을 열지 않고도 양방향 통신이 가능하고 HTTP 규격인 CORS 적용이나 인증 등의 과정을 기존과 동일하게 가져갈 수 있는 것이 장점이다. 이로 인해 보안과 호환성이 뛰어나고, SSL/TLS 적용으로 안전한 통신 또한 가능하다.

 

✔️ 낮은 오버헤드

첫 연결 시 HTTP Handshake로만 연결을 설정한 후, 헤더 없이 데이터 전송한다. HTTP Polling과 비교했을 때 요청-응답 방식의 오버헤드가 없다. 웹소켓을 사용하면 데이터가 사용 가능한 즉시 전송된다. 클라이언트가 데이터를 계속 요청할 필요도 없다. 그 결과로 오버헤드와 네트워크 트래픽에서의 지연 시간이 훨씬 짧아진다.

 

✔️ 상태 저장 Stateful Connection

지속적인 연결로 세션 상태를 유지할 수 있어서 다른 방식에 비해 반복 인증 없이 상호작용이 가능하다. 사용자 컨텍스트 또한 지속적으로 활용 가능하다.

 

⚠️ 유의할 점은 초기 설정이 복잡하다. 서버 및 클라이언트의 추가 코드가 필요하고 비활성화된 클라이언트에 대한 연결 관리도 구축해놓아야 하며, 연결 유지 비용 또한 무시할 수 없다. 그리고 서버리스 환경에 적용할 경우 대규모 연결 처리시 이 또한 비용이 증가할 수 있다. 

 

Server-Sent Events (SSE)

https://turkogluc.com/server-sent-events-with-spring-boot-and-reactjs/

 

 

전통적으로 웹 페이지는 서버에 요청을 보내서 새로운 데이터를 수신해야 한다. 페이지에서 서버로 데이터를 요청하는 방식. 하지만 웹 애플리케이션을 개발하다보면 클라이언트의 요청이 없어도 서버에서 데이터를 전달해줘야 하는 경우가 있다. 뉴스피드나 댓글 알림 등 실시간으로 서버의 변경사항을 웹 브라우저에 갱신해줘야 하는 경우 등! 

 

SSE는 클라이언트가 HTTP 연결을 통해 서버로부터 자동 업데이트를 수신할 수 있도록 하는 Server Push 기술이며, 클라이언트 연결이 한 번 설정되면 서버에서 변경이 발생할 때마다 클라이언트로 데이터를 전송할 수 있다. 이는 응답마다 다시 요청을 해야하는 Long Polling 방식보다 대부분의 케이스에서 효율적이다. 

 

✔️ 단방향 통신 One-way communication

서버에서 클라이언트로만 데이터를 전송할 수 있다. 클라이언트에서 데이터를 전송하지 않고 서버의 데이터만 클라이언트로 보내서 업데이트를 해야하는 경우에 적합하다. 긴 시간이 걸리는 요청에 대해서 요청을 일부분 나눠서 보내는 등

 

✔️ 텍스트 기반 프로토콜

SSE는 HTTP 프로토콜을 기반으로 하여 동작하여 바이너리 데이터를 전송하기 위해서는  추가적인 인코딩이 필요하다.

 

✔️ 자동 재연결 지원 Automatic Reconnection

연결이 끊어지면 브라우저에서 자동으로 재연결을 시도한다. Last-Event-ID 헤더를 사용해 끊어진 지점부터 데이터를 이어받을 수 있다.

 

✔️ 낮은 오버헤드

HTTP 기반으로 설정이 간단하고 웹 브라우저와의 호환성이 뛰어나다. WebSocket과 비교했을 때 설정 복잡도가 낮아서 러닝커브때문에 SSE를 선택한 경우도 종종 보인다. 특별한 프로토콜이나 서버구현이 필요하지 않기 때문.

 

⚠️ 유의할 점은 HTTP/2의 멀티플렉싱이 지원되지 않으면 다수의 SSE 연결이 서버에 부담을 줄 수 있다는 것. 양방향 통신을 원할 경우 고려하기 어렵다는 점. 

 

Polling, SSE, WebSocket 상호 전환 가능할까?

HTTP Polling ⇌ SSE

✅ 단방향 데이터 전송 방식

⚠️ SSE는 persistent connection으로 동작, 주기적인 요청이 필요하지 않다. SSE에서 Polling으로 전환할 경우 요청을 필수적으로 해야하기 때문에 성능상에서의 이점이 사라질 수 있다.

HTTP Polling ⇌ WebSocket

⚠️ Polling은 Request/Response의 주기를 기반으로 하지만 WebSocket처럼 persistent connection을 위해선 앱 로직을 재설계 해야한다. 

⚠️ 물론 요청 주기를 짧게 설정하면 가능할 순 있다. 하지만 위에서 설명했듯 부하가 증가하여 비효율적이다.

SSE ⇌ WebSocket

✅ persistent connection 유지, 데이커 전달.

✅ HTTP 기반으로 네트워크 설정이 유사하다. (WebSocket에서의 전환은 쉬울 수 있으나 반대는 어려울 수 있다)

⚠️ 양방향 통신이 필요한 경우 SSE로는 구현이 불가능하다. 

⚠️ WebSocket은 바이너리 데이터를 지원하지만 SSE는 텍스트 기반에 적합하다.

 

결론은.. 목적에 맞게 처음부터 잘 구현하는 것이겠다.

서버리스 환경에서 적용할 수 있는가? YES

서버리스를 처음에 서버가 아예 없는 것으로 착각했다..!!!!! 서버리스에 대해 먼저 알아보자.

 

서버리스 Serverless란 클라우드 컴퓨팅의 모델 중 하나로 개발자가 서버를 관리할 필요 없이 애플리케이션을 빌드하고 실행할 수 있도록 하는 아키텍처이다. 동적으로 서버의 자원을 할당하는데, 예를 들면 사용자가 없을 경우 자원을 할당하지 않고 대기하다 요청이 들어오면 그때에 자원을 할당해서 요청을 처리하고 다시 대기 상태로 들어가게 된다. 

비용 또한 대기상태를 제외한 실제 사용 자원에 대해서만 청구되기 때문에 경제적이며 해당 서버는 클라우드 제공 기업(AWS 등)에서 전적으로 관리하기 때문에 개발자는 서버에 대해 신경 쓸 필요가 없는 것이다.

 

https://serverlessland.com/patterns/apigw-websocket-api-lambda?ref=search

 

WebSocket, Polling, SSE 전부 서버리스 환경에서 적용할 수 있다. 하지만 각각의 설정 난이도와 사용 목적에 따라 차이가 있다.

Polling의 경우 HTTP Request/Response 기반으로 작동하여 Serverless 함수(API Gateway + Lambda)와 가장 자연스럽게 연결 가능하다. 하지만 주기적인 요청이 있기 떄문에 비용이 높게 발생할 수 있다. SSE 또한 HTTP 기반으로 상대적으로 쉽게 연결할 수 있다. WebSocket의 경우 AWS Gateway WebSocket API 덕분에 이전보다 훨씬 쉬워졌다고 할 수 있음에도 Polling과 SSE와 다르게 추가 설정할 부분이 많기때문에 셋 중 제일 연결이 여전히.. 어렵다.

 


🧐

먼저, 알버트 덕분에 새롭게 공부할 수 있었다 Thx!!!! 알버트에게 제대로 된 답변이길 바라며 글을 마친다.
WebSocket을 실무에서 잠시 사용해보았기 때문에 SSE와 Polling 같은 대안을 생각해보지 못했는데 이젠 어떤 목적에 따라 어떤 것을 적용할 수 있을지 고민해볼 수 있게 되었다. 또한 WebSocket을 알아보다보니 WebRTC를 공부해보고 싶어졌다. 다음에 기회가 된다면 WebRTC로 간단한 애플리케이션을 만드는 것을 포스팅 해보고싶다.

또한 서버리스 부분에 대해 기초 지식이 부족하여 제대로 설명할 수 없었던 것은 아쉽다. 이런 부분도 추후에 잘 채워나가보려한다...! AWS 공부에 대한 필요성을 또 깨닫는 중..

 

 

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-Polling-Long-Polling-Server-Sent-Event-WebSocket-%EC%9A%94%EC%95%BD-%EC%A0%95%EB%A6%AC

https://usingsystem.tistory.com/45

https://sendbird.com/developer/tutorials/websocket-vs-http-communication-protocols 

https://en.wikipedia.org/wiki/Server-sent_events  

https://tecoble.techcourse.co.kr/post/2022-10-11-server-sent-events/  

https://kwseo.github.io/2017/03/25/sse/

https://dev-coco.tistory.com/171