본문 바로가기
Dev/Node.js

서비스에 실시간 통신을 도입한 과정

by Sovereign 2024. 7. 19.

실시간 통신이 필요했던 이유

최근 담당하고 있는 프로젝트의 대시보드 일부 기능에 대해 실시간 통신을 적용해야 되는 상황이 발생했다. 유저에게서 다음과 같은 불편함을 문의받았다.

기존 조회 방식은 HTTP 프로토콜을 사용하여 5초마다 143KB의 브라우저 캐시를 폴링(polling)하는 방식인데. 이에 따라, 모니터링 인원이 대시보드를 장시간 사용 시 브라우저 메모리가 증가하여 성능 저하가 발생하는 문제가 발생합니다. 개선해 줄 수 있나요?

 

위 문제를 해결하기 위해서는 Long Polling이나 Server-Sent Events (SSE) 같은 방법들도 존재했지만, 경고를 식별하고 Escalation 하는 기능에서는 적합하지 않았다. 이유는 다음과 같았다.

 

  • Long Polling 방식 또한 기존 Polling 방식과 동일하게 지속적인 요청과 응답으로 인해 서버 부하가 증가할 수 있다는 점에서 적합하지 않았다.
  • Server-Sent Events (SSE) 방식은 클라이언트에서 서버로의 데이터 전송이 불가능하다는 점에서 선택하지 않았다.

 

 

 

실시간 통신에 Node.js를 선택한 이유

대시보드의 Escalation 기능을 사용하는 유저는 150명 미만이다. 실질적으로 8시간 교대 모니터링이기에 동시에 모니터링하는 인원은 3~5명이다. 또한 서비스 초기이기 때문에 대용량 데이터가 존재하지 않으며, 대용량 트래픽이 발생하는 구조가 아니다. VPN - SSO 인증을 통해 사전에 여러 인증 절차를 진행한 유저만 서비스에 접근하기 때문에 유입되는 트래픽이 일정하다.

 

위와 같은 이유로 실시간 통신을 구축하기 위해 Socket.IO에 대한 이해도가 받침 된다면 Node.js 또한 괜찮은 선택이라 판단하여 선택하게 되었다.

 

 

 

 

우선 Socket.IO에 대한 기본적인 개념을 살펴본 뒤, 실무 프로젝트에 어떻게 적용했는지 간단한 예제를 통해 살펴보자.

Socket.IO란

Socket.IO는 웹 소켓 연결을 통해 클라이언트와 서버 간에 실시간 양방향 통신을 가능하게 하는 JavaScript 라이브러리다.

 

 

Socket.IO 주요 개념

Socket.IO 기본 개념

 

Socket : 소켓은 클라이언트와 서버 간의 연결을 나타내는 추상화된 객체로, 이를 통해 양방향으로 실시간 데이터를 주고받을 수 있다. 소켓은 이벤트 기반 통신을 가능하게 하여, 특정 이벤트를 방출하거나 수신할 수 있다. 예를 들어, 소켓을 사용하면 채팅 메시지를 보내거나 다른 사용자의 입력을 실시간으로 수신할 수 있다.

 

Server : 서버는 클라이언트와의 소켓 연결을 설정하고 관리하며, 여러 클라이언트와의 연결을 동시에 처리할 수 있다. 서버는 클라이언트의 연결 요청을 수락하고 연결을 유지하며, 클라이언트로부터 이벤트를 수신하고 이를 처리한다. 또한, 서버는 클라이언트로 이벤트를 방출하여 실시간으로 데이터를 전송할 수 있다. 예를 들어, 채팅 서버는 새로운 메시지가 도착했을 때 모든 클라이언트에게 이를 알릴 수 있다.

 

Client : 클라이언트는 서버와의 소켓 연결을 설정하고 관리하는 역할을 한다. 클라이언트는 서버에 연결을 요청하고, 연결을 유지하며, 서버로 이벤트를 방출하여 데이터를 전송한다. 또한, 클라이언트는 서버로부터 이벤트를 수신하여 이를 처리한다. 예를 들어, 웹 애플리케이션의 클라이언트는 사용자가 채팅 메시지를 입력하면 이를 서버로 전송하고, 서버에서 다른 사용자의 메시지를 수신하여 화면에 표시할 수 있다.

 

 

Socket.IO 트래픽 격리 구분

 

Event : 이벤트는 소켓 연결을 통해 클라이언트와 서버 간에 전송되는 메시지다. 이벤트 이름은 서버와 클라이언트에서 동일하게 선언되어야 한다. 이벤트는 JSON, 문자열, 이진 데이터 등 모든 형식의 데이터를 포함할 수 있다.

 

Namespace : 네임스페이스는 클라이언트와 서버 간의 별도의 통신 채널이다. 단일 서버에서 여러 네임스페이스를 작성할 수 있으며, 클라이언트는 특정 네임스페이스에 연결하여 해당 네임스페이스의 다른 클라이언트에게만 이벤트를 수신하거나 방출할 수 있다. 이를 통해 서버에서 통신을 격리하고 효율적으로 관리할 수 있다.

 

Room : 룸은 함께 결합된 소켓 그룹이다. 소켓은 여러 룸에 합류하거나 떠날 수 있다. 룸은 연결된 모든 클라이언트에게 방송하는 대신 특정 클라이언트 그룹에 메시지를 보내는 데 유용하다. 이를 통해 메시지를 특정 사용자 그룹에게만 전송할 수 있어 효율적인 통신이 가능하다.

 

 

Socket.IO 이벤트 송수신 방식

Public (브로드캐스트)

  • 연결된 모든 클라이언트에게 메시지를 전송한다. io.emit을 사용하여 연결된 모든 클라이언트에게 메시지를 브로드캐스트 할 수 있다.

 

 

Private (개인 메시지 송신)

  • 특정 클라이언트에게만 메시지를 보낸다.
  • socket.emit을 사용하여 특정 클라이언트에게 메시지를 전송할 수 있다.
  • io.to(recipientId).emit을 사용하여 특정 클라이언트에게 메시지를 보낸다.

 

 

Broadcasting (발신자를 제외한 브로드캐스트)

  • 발신자를 제외한 모든 클라이언트에게 메시지를 전송한다.
  • socket.broadcast.emit을 사용하여 발신자를 제외한 연결된 모든 클라이언트에게 메시지를 브로드캐스트 할 수 있다.

 

 

서버 측에서의 이벤트 핸들링

  • io.on('connection', callback)는 새로운 클라이언트가 연결될 때 호출된다. callback 함수의 인자로 연결된 클라이언트의 socket 객체가 전달된다.
  • socket.on('event', callback)는 클라이언트로부터 특정 이벤트를 수신할 때 호출된다. callback 함수의 인자로 이벤트 데이터가 전달된다.

 

클라이언트 측에서의 이벤트 핸들링

  • socket.on('event', callback)는 서버로부터 특정 이벤트를 수신할 때 호출된다. callback 함수의 인자로 이벤트 데이터가 전달된다.

 

 

 

Socket.IO 이벤트 송수신 개념

Emit : 이벤트를 발생시키는 메서드로, 클라이언트나 서버 모두에서 사용된다. 주로 데이터를 전송할 때 사용된다.

 

 

To 특정 소켓 ID나 방에 이벤트를 발생시키기 위한 메서드다. 이 메서드는 서버에서 주로 사용된다.

 

 

On 이벤트 리스너를 등록하는 메서드로, 이벤트가 발생할 때 실행될 콜백 함수를 정의한다. 클라이언트와 서버 모두에서 사용된다.

 

 

 

 

Of : 네임스페이스를 생성하는 메서드로, 네임스페이스를 통해 논리적으로 소켓을 분리하고 관리할 수 있다.

 

 

 

Socket.IO 동작 방식

 

Socket.IO는 클라이언트와 서버 간의 실시간 양방향 통신을 가능하게 하는 라이브러리로, 주로 WebSocket 프로토콜을 사용하지만, 초기 연결 설정에서는 다양한 전송 메커니즘을 사용하여 폴백(fallback) 기능을 제공한다. Socket.IO의 작동 방식은 클라이언트와 서버 간의 연결 설정, 이벤트 기반 통신, 방과 네임스페이스를 통한 논리적 구분, 그리고 연결 종료의 네 가지 주요 단계로 나눌 수 있다.

 

 

1. 연결 설정

  • 클라이언트는 HTTP 폴링을 통해 서버에 초기 연결을 설정한 후 WebSocket으로 업그레이드한다. 이를 통해 양방향 통신 채널이 형성되어 실시간 데이터 송수신이 준비된다.

2. 이벤트 기반 통신

  • 클라이언트와 서버는 각각 이벤트를 방출(emit)하고 수신(on)하여 데이터를 주고받는다. 이를 통해 메시지, 알림, 데이터 업데이트 등을 실시간으로 처리한다.

3. 방(Rooms)과 네임스페이스(Namespaces)를 통한 논리적 구분

  • 네임스페이스는 서로 다른 기능을 독립적으로 운영할 수 있도록 구분한다. 방(Room)은 특정 클라이언트 그룹에만 이벤트를 전송하여 효율적인 그룹 통신을 가능하게 한다.

4. 연결 종료

  • 클라이언트 또는 서버는 언제든지 연결을 종료할 수 있으며, disconnect 이벤트를 통해 연결 종료를 감지한다.

 

 

 

어떻게 만들었나

robot.js

robot.js는 주기적으로 HTTP 요청을 보내 Go 서버의 상태를 확인하고, 그 결과를 실시간으로 다른 클라이언트에 전송하는 역할을 한다.

 

socket.io-client 모듈을 사용하여 클라이언트를 설정하고, 환경 변수로 서버 URL을 지정한다. username과 room 변수를 설정한 후, 클라이언트가 서버에 연결되면 joinRoom 이벤트를 통해 지정된 방에 입장한다.

 

 

 

5초마다 HTTP 요청을 보내며, 요청 본문에 status: "OPEN"을 포함한 payload 객체를 전송한다. 요청 응답에서 TotalRows 값을 추출한 후 서버로 전송한다.

 

 

 

server.js

server.js는 Socket.IO 서버를 설정하고, 클라이언트로부터 받은 메시지를 실시간으로 처리한다.

 

http와 express 모듈을 사용하여 서버를 설정하고, socket.io를 통해 실시간 통신 서버를 설정한다. 서버는 특정 경로(/socket.io)와 CORS 설정을 사용하여 클라이언트와 통신한다.

 

 

 

클라이언트가 연결되면 joinRoom 이벤트를 통해 특정 방에 참여한다. chatMessage 이벤트를 통해 클라이언트로부터 메시지를 수신하고, 같은 방에 있는 다른 클라이언트에게 전송한다. 클라이언트가 연결을 끊으면 disconnect 이벤트를 처리하여 해당 클라이언트가 방을 떠났음을 알린다.

 

 

 

Deep Dive

Socket.IO와 WebSocket은 어떻게 다른가?

  • Socket : 소켓은 TCP/IP 레이어에서 양방향 통신을 위한 연결체다. 이를 통해 클라이언트와 서버 간의 데이터 교환이 가능해진다.

  • WebSocket : WebSocket은 HTTP 프로토콜을 통해 연결 요청을 시작하는 양방향 통신 프로토콜이다. 한 번 연결이 설정되면, 지속적인 TCP 연결을 통해 클라이언트와 서버가 실시간으로 데이터를 주고받을 수 있다.

  • Socket.IO : Socket.IO는 WebSocket을 기반으로 한 실시간 양방향 통신 라이브러리다. WebSocket이 지원되지 않는 환경에서는 HTTP 롱 폴링과 같은 폴백 메커니즘을 통해 통신을 유지할 수 있다. Socket.IO는 자동 재연결, 이벤트 기반 통신, 방과 네임스페이스와 같은 추가적인 기능을 제공한다.

 

 

 

의도치 않게 소켓 통신이 중단되면 어떻게 처리할 것인가?

의도치 않게 소켓 통신이 중단되는 경우를 처리하는 방법은 여러 가지가 있다. 이 문제를 해결하기 위해 주로 자동 재연결, 에러 핸들링, 타임아웃 설정 등을 사용한다.

 

 

자동 재연결

자동 재연결은 소켓 연결이 끊어졌을 때, 클라이언트가 자동으로 서버에 다시 연결을 시도하는 기능이다. Socket.IO는 기본적으로 자동 재연결을 지원한다.

Socket.IO 클라이언트는 자동 재연결을 설정할 수 있다. 기본 설정으로 자동 재연결이 활성화되어 있지만, 재연결 시도 횟수와 간격 등을 설정할 수 있다.

 

 

에러 핸들링

에러 핸들링은 소켓 통신 중 발생할 수 있는 에러를 처리하는 방법이다. 에러를 적절하게 처리하여 사용자에게 알리거나 재연결을 시도할 수 있다.

 

 

타임아웃 설정

타임아웃 설정은 연결 시도 중 일정 시간이 지나도 연결이 이루어지지 않을 경우, 연결 시도를 중단하고 에러를 발생시키는 설정이다. 이를 통해 불필요한 연결 시도를 줄이고, 사용자에게 연결 상태를 명확히 알릴 수 있다.


 

출처

Socket.IO Deep Dive. Everything You Need To Know About… | by Eve Martin | Ably: Serious, serverless realtime infrastructure | Medium

 

Socket.IO Deep Dive

Everything You Need To Know About Socket.IO

medium.com

socket.io 딥다이브 - 개념과 이해 (tistory.com)

 

socket.io 딥다이브 - 개념 과 이해

최근 이직을 위해 면접을 보러 다니는 중에 웹소켓에 관한 질문을 받은 적이 있다. socket.io를 이용해서 실시간 채팅 서비스를 만들었고 그 과정에서 웹소켓에 관한 공부를 진행한적이 있는데, 막

hoime.tistory.com

 

 

https://medium.com/ably-realtime/socket-io-deep-dive-8a6a4d0877de

 

Socket.IO Deep Dive

Everything You Need To Know About Socket.IO

medium.com

Socket.IO - client(주요 개념, 작동방식, 트래픽 격리 구분, 이벤트 송수신) (velog.io)

 

Socket.IO - client(주요 개념, 작동방식, 트래픽 격리 구분, 이벤트 송수신)

→ Socket.IO는 웹 소켓 연결을 통해 클라이언트와 서버간에 실시간 양방향 통신을 가능하게하는 JavaScript 라이브러리입니다. Socket.IO는 클라이언트와 서버 간의 실시간 통신을 위한 사용하기 쉬운

velog.io