Skip to content

실시간 채팅 구현 방식에 대한 고민

Chanhee Kim edited this page Dec 10, 2021 · 2 revisions

고민

프로젝트를 진행하면서 실시간 채팅을 구현 하게되었고, 이를위해 실시간 채팅을 지원하는 서비스들을 조사해본 결과,

  • HTTP 송신/WebSocket 수신 : Slack, Discord
  • WebSocket 송수신 : Facebook, Instagram

실시간 채팅 메시지 송수신 방법이 위 두가지 방법으로 나뉘어 있다는 것을 알게 되었습니다.

추가로 쇼핑 라이브 역시 채팅 메시지 전송시 아래와같이 HTTP 요청을 보내고 있는 것을 확인했습니다.

image image

Slack과 Discord 서비스와 같이 HTTP로 메시지를 송신하는 방식은 전이중통신이 가능한 WebSocket의 이점을 제대로 살리지 못하고, 성능 부분에서 손해를 보게되는데, 위 서비스들에서는 이러한 성능적인 이점을 놓치며 HTTP로 송신하는 방법을 택했는지 의문이 들었습니다. 때문에 WebSocket을 통한 송신이 어떤 단점을 갖고 있는지, 즉 HTTP 로 송신을 했을 때 어떤 이점을 가져갈 수 있을 지 생각해봤습니다. 

첫번째로, 서드파티 애플리케이션 때문이라고 생각을 하였습니다.서드파티 애플리케이션의 경우 많은 통신을 주고받지 않는 경우가 있는데, 예를 들어 부스트캠프에서 사용되었던 출첵알리미 봇의 경우 아침과 저녁 두번만 메시지를 보내면 되고, 이를 위해 WebSocket연결을 유지하는 비용(TCP 소켓 점유, 연결 상태를 메모리에 저장하고 있어야함)이 HTTP 요청에 필요한 비용보다 더 크기때문에 WebSocket을 사용하는 것이 오히려 비효율적입니다. 위와 같은 경우를 고려해 다양한 서드파티 애플리케이션을 지원하는 디스코드, 슬랙의 경우 이런 방식을 채택한것이 아닌가 생각했습니다.하지만 서드 파티를 위한 HTTP API를 별도로 제공하고, 일반 사용자들의 경우 WebSocket을 사용해 채팅 메시지 송수신을 처리 하도록 구현하면 해결할 수 있는 문제라고 생각했고, facebook과 instagram에서도 서드파티를 위한 메시지 송신 HTTP API를 제공해 해결한 것을 확인했습니다. 따라서 서드 파티를 위해 HTTP를 사용하여 모든 메시지 송신을 하도록 구현한 것은 아닐 것 이라는 결론에 도달했습니다. 

두번째로, HTTP는 요청 실패에 대한 처리가 용이하기 때문이라고 생각을 하였습니다. HTTP 요청은 어떤 요청이 실패했는지 응답을 통해 쉽고 확실하게 알 수 있어서 요청 실패에 대한 처리가 수월하나, 소켓의 경우 실패시 처리를 위해서 이벤트마다 ID를 부여하는 것(어떤 이벤트를 처리하지 못했는지 알기위해) 등과 같은 별도의 장치가 필요해 복잡도가 증가하기 때문에 HTTP를 사용하지 않았을까 생각하였습니다. 

세번째로, 확실한 사용자 인증을 위해 HTTP를 사용하지 않았을까 라는 생각을 하였습니다. WebSocket의 경우 처음 소켓 연결을 위한 과정에서만 쿠키를 전달받기때문에 연결 이후 클라이언트에서 쿠키 정보가 변경되어도 알 수 없기 때문에 확실한 인증이 어렵다고 생각했습니다. 그런데 메시지 송신의 경우 DB에 쓰기작업을 하기 때문에 인증을 확실하게 해야한다고 생각했고, 이를 해결하기위해선 클라이언트에서 쿠키 변경이 감지되면, 소켓 연결을 끊도록 하는 등의 조치가 필요하다고 생각했습니다. 하지만 HTTP의 경우 매번 쿠키를 전달 받기 때문에 이러한 문제를 고려하지 않아도 된다는 이점이 있다고 생각했습니다.

결론

위와같이 실시간 채팅을 지원하는 여러 서비스들에서 WebSocket이 아닌 HTTP를 통해 메시지를 송신하는지 생각해보았고, 성능을 조금 손해보더라도 두번째와 세번째 이점을 가져가는게 저희 프로젝트에 좋겠다고 판단했습니다.

그렇게 판단한 이유는 다음과 같습니다.

  1. 일반적인 네트워크 환경에서 서비스를 사용시 HTTP와 WebSocket을 통한 송신 방식간 성능차이를 체감하기 힘들다고 생각했습니다.
  2. WebSocket, WebRTC 와 같은 실시간 통신 기술이 많이 사용되고, 서버로 부터 비동기로 값을 받아와야하는 상태들이 많아 복잡도가 낮은 방법으로 구현하는 것이 좋겠다고 판단했습니다. 실패에 대한 처리와 확실한 인증을 보다 쉽게 할 수 있는 HTTP를 사용하는 것이 좋겠다고 판단했습니다. 특히 인증의 경우 DB에 쓰기 작업을 하기 때문에 확실히 해야한다고 판단했고, HTTP의 경우 express-session 미들웨어를 사용해 쉽게 session이 유효한지 확인 할 수 있으나, 소켓의 경우 이벤트 핸들러에 첫 연결시 전달받은 세션 정보가 유효한지 DB를 탐색해 확인하는 작업, 클라이언트에서 쿠키 변경이 감지되었을 때 소켓을 끊어주는 등 조치를 취해주기 위한 코드들을 추가로 작성해야해 복잡도가 크게 증가할 것이라 생각했습니다.
Clone this wiki locally