웹 소켓 & SSE(Server Sent Events)

2024. 6. 10. 02:10개인 공부

 

웹 소켓과 SSE를 알아보기 전, 우선 클라이언트와 서버 간의 HTTP 통신에 대해 알아봅시다.

 

HTTP 통신

HTTP 1.1 이하에서는 클라이언트가 서버에게 요청을 보내고, 응답을 받는 단방향 통신만 가능했습니다.

즉 서버가 클라이언트에게 메시지를 보내기 위해서는, 먼저 요청을 받아야 했습니다.

 

위 방식은 상황에 따른 한계도 분명 존재합니다. 다음 예시를 봅시다.

 

채팅 앱 

  • 내가 상대방에게 메시지를 보내려면 클라이언트에서 서버로 요청을 보내면 된다. OK
  • 내가 상대방의 메시지를 보려면 어떻게 해야 할까? 내가 요청을 보내야지만 응답을 받을 수 있다면서..

HTTP 에서는 이 문제를 Polling(폴링)으로 해결할 수 있습니다.

 

Polling

출처 : https://jaehyeon48.github.io/network/polling-and-sse

 

 

Polling 을 통해 클라이언트가 주기적으로 서버에게 요청을 보내, 상대방이 새로운 채팅을 보냈는지 확인할 수 있습니다.

서버는 클라이언트의 각 요청에 대해 즉각적으로 응답합니다.

 

 

Polling 의 단점

  • 요청의 주기만큼 딜레이가 발생합니다. 따라서 클라이언트는 서버의 상태 변화를 실시간으로 따라갈 수 없습니다.
  • 계속해서 요청과 응답을 주고 받으므로, 트래픽이 낭비됩니다.

 

Long Polling

폴링의 단점을 개선한 폴링 방식입니다. 서버가 클라이언트의 요청에 바로 응답하지 않고 업데이트가 발생할 때까지 기다립니다.

Time-Out 혹은 상대방이 챗을 보내면 응답을 보내고, 클라이언트가 다시 요청을 보내 다음 응답을 기다립니다.

 

 

단점

  • 서버의 업데이트를 빠르게 따라잡을 수 있지만, 서버의 부담이 너무 크다!
  • 연결을 유지해야 하므로, 클라이언트가 많다면 서버는 많은 연결을 유지해야 하고, 자원 소모가 너무 크다는 단점이 있다.

 

위처럼 Polling 으로 채팅과 같이 양방향으로 티키타카하는 서비스를 구현할 수는 있겠으나, 자원을 너무 많이 소모하게 됩니다.

채팅 서비스를 제대로 구현하려면 클라이언트와 서버 간의 양방향 통신이 필요하고, 이때 등장하는 개념이 웹 소켓입니다.

 

 

Web Socket

서로 동등한 입장에서 메시지를 주고받을 수 있게 해주는 것이 바로 웹 소켓입니다.

채팅 앱과 같이 장시간 양방향 통신에 적합한 프로토콜로, 소켓 통신은 다음 방식으로 이뤄집니다.

출처 : https://ko.wikipedia.org/wiki/웹소켓

 

클라이언트 서버 간의 HandShake를 통해 연결이 이뤄집니다. (클라이언트가 HTTP -> ws 로 프로토콜 업그레이드 제안)

연결이 수립되면 이때부터 클라이언트 서버는 HTTP 가 아니라 웹 소켓 통신(ws://)을 통해 메시지를 주고받습니다. 연결 종료는 한쪽이 close 를 보내고, 다른 한 쪽이 이를 확인해 응답하면 연결이 종료됩니다.

 

 

장점

  • 웹 소켓은 하나의 연결을 끝까지 유지하고, 적은 자원만 소모하기 때문에 Long Polling 만큼 서버에 부담을 주지 않습니다.

따라서 웹 소켓을 사용해 채팅 앱과 같은 서버로부터 실시간 업데이트가 필요한 서비스들을 효율적으로 구축할 수 있으며, 웹 소켓에서의 통신은 TCP를 사용하기 때문에 데이터의 순서와 신뢰성이 보장됩니다.

 

 

단점

로드밸런서가 적용된 서버에서는 구현이 복잡할 수 있습니다. 한 서버와 웹 소켓 통신을 시작하면 이후로도 계속 그 서버로만 데이터가 전송되도록 해야하니까요. 이럴 땐 NginX, AWS ELB 같은 것들로 해결할 수 있다고 합니다.

 

그리고 웹 소켓도 서버에 부담을 주는 건 마찬가지입니다! Long Polling 방식보다는 덜하지만, 사용자가 많아져 유지해야 하는 TCP 연결의 수가 많아진다면 이는 서버의 부담으로 이어질 것입니다.

 


SSE (Server Sent Events)

서비스의 특징에 따라 웹 소켓의 대안이 될 수 있는 방식입니다.

웹 소켓처럼 양방향 통신이 아닌, 서버로부터의 단방향 통신으로 이뤄진 서비스의 경우 고려해볼 수 있습니다.

 

SSE 는 서버쪽에서 클라이언트로 실시간으로 데이터를 보내줍니다.

  • 프로그램 설치 로딩 바, SNS 실시간 피드, 뉴스 페이지 등 많은 경우에 적합한 방식이 될 수 있습니다.

출처 : https://velog.io/@coastby/네트워크-SSE로-구현하는-채팅

 

SSE 동작 방식은 웹 소켓에 비해 단순합니다.

클라이언트가 서버에 요청을 보냅니다 : "지금부터 데이터를 보내줘. 나는 네가 주는 메시지를 받기만 할게"

서버는 이를 확인하고 클라이언트에게 ok 사인을 보냅니다. 이후 클라이언트는 서버에서 메시지를 수신할 준비를 합니다.

 

 

이 시점부터, 서버는 정해진 이벤트가 있을 때마다 클라이언트에세 메시지를 보내게 됩니다.

클라이언트는 서버의 메시지에 응답을 하지는 않고, 서버로부터 메시지가 도착할 때마다 이에 반응하여 화면을 업데이트 하는 등의 작업을 수행하게 됩니다.

 

이 모든 과정은 하나의 연결 안에서 이뤄지며, 연결이 끊기면 클라이언트는 서버에게 재연결을 요청합니다. HTTP 를 통해 통신이 이뤄지며, 웹 소켓에 비해 덜 복잡합니다.

 

또한 분산 환경에서도 WebSocket 과는 달리, 서버에서 클라이언트로 보내면 되므로 어려움이 없습니다.

웹 소켓에서는 로드밸런서를 신경써야 했지만 SSE 는 그럴 필요가 없습니다!

 

헤더

클라이언트에서 서버로 'Accept: text/event-stream' 이라는 헤더를, 서버가 응답으로 'Content-Type: text/event-stream' 이라는 

헤더를 응답으로 보냅니다. 헤더에는 연결을 계속 유지한다는 뜻인 Connection: keep-alive 도 실어 보냅니다.

 

해당 헤더로 인해 클라이언트가 요청을 보내면서 만들어진 연결이, 서버가 응답을 보낸 이후로도 계속 유지된다고 합니다.

이렇게 하나의 TCP 연결을 맺고, 서버가 첫 번째로 응답한 이후부터는 메시지에 HTTP 헤더가 실릴 필요가 없어 부담도 적습니다.

 

서버는 지정된 이벤트가 발생할 때마다 실시간으로 클라이언트에게 메시지를 보내고, 클라이언트에서는 EventSource가 메시지를 받게 됩니다.

 

연결 종료

  • 클라이언트에서 종료할 때에는 EventSource 객체의 close() 메서드를 호출한다.
  • 서버쪽에서 종료하려면 전송을 중단하거나, 클라이언트에게 합의된 메시지를 보내면 된다.

 

결론

웹 소켓과 SSE 기법에 대해 알아보았습니다. 

웹 소켓은 채팅처럼 양방향 통신에서 많이 사용되고, 클라이언트와 서버 간 실시간 메시지 전송에 적합하다는 것을 알았습니다. 

하지만 연결이 많아질 경우 서버에 부담을 주고, 로드밸런서가 있는 분산 환경에서는 구현하기 복잡할 수 있습니다.

 

SSE(Sever-Sent-Events) 방식은 소켓의 단점을 보완한 방법으로, 서버에서 클라이언트로 데이터를 쏴주기 때문에 더 간편하고 헤더가 필요없기 때문에 트래픽이 절감됩니다. 

양방향 통신이 굳이 필요하지 않은 경우라면 SSE 를 사용하는 것도 좋은 방법일 것 같습니다. (:

 

 

 

References

https://ko.wikipedia.org/wiki/웹소켓

https://velog.io/@coastby/네트워크-SSE로-구현하는-채팅

https://developer.mozilla.org/en-US/docs/Web/API/EventSource

https://developer.mozilla.org/ko/docs/Web/API/Server-sent_events/Using_server-sent_events