SpringBoot + Stomp + RabbitMQ로 실시간 채팅 구현하기

의혁·2025년 2월 12일
post-thumbnail

💡 Stomp에 외부 메시지 브로커인 RabbitMQ를 붙여서 실시간 채팅을 구현하여 보자!

1. 🙋🏻개요

앞선 포스팅에서는 Stomp를 이용하여서 실시간 채팅을 구현하였다.
Stomp는 "Simple Broker라는 내부 메시지 브로커"를 사용하여 메시지를 처리하고, 따로 외부 메시지 브로커를 사용하지 않는다.
실제로 사용자가 많지 않은 간단한 프로젝트의 경우에는 Stomp로만 채팅을 구현하여도 문제가 되지 않지만, 사용자 수가 많아져서 처리해야 할 메시지들이 많아진다면 이를 하나의 Spring Boot가 실행되고 있는 "Simple Broker"로 감당 해야한다. ( 서버의 Memory 사용 )
이는 다른 비즈니스 로직도 구현되어 있는 하나의 서버에 너무 많은 부담을 안기게 됨으로 이를 해결하기 위해 "외부 메시지 브로커"를 사용한다.

또한, Simple Broker는 In-Memory 기반이므로, 갑작스럽게 서버가 Down되면, 내부의 데이터들을 모두 유실한다.

현재 진행중인 "snail" 프로젝트에서도 많은 사용자들이 채팅기능을 이용하기 떄문에, 다른 서버에서도 메시지를 구독하여 받아 볼 수 있으며, 서버의 부담을 줄이기 위해 "RabbitMQ"를 적용 해보고자 한다.


2. 🤔What is RabbitMQ?

1) RabbitMQ

  • RabbitMQ는 오픈 소스 기반 "메시지 브로커 소프트웨어"로 분산 시스템에서 메시지 or 데이터를 전달하기 위한 매개체이다.
  • RabbitMQ는 "AMPQ"를 기반으로 하며 다양한 프로그래밍 언어와 플랫폼에서 사용할 수 있다.
  • RabbitMQ는 "메시지 큐"를 사용하여 Producer 와 Consumer 사이에서 "비동기 통신"을 통해 메시지를 큐에 저장하고, 독립적으로 작동할 수 있다.

2) AMQP(Advanced Message Queuing Protocol)

  • "AMQP"메시지 기반의 통신을 위한 프로토콜이며, 메시지 전송을 위한 규칙 (큐, 라우팅, 교환패턴등)을 정의한다.
  • 메시지를 비동기적으로 처리할 때 분산 시스템에서의 안정적인 데이터 전송을 보장한다.
  • "메시지의 우선순위", "라우팅", "트랜잭션" 등 다양한 기능을 제공한다.

3) ⭐️ AMQP를 사용한 RabbitMQ 분산 처리 과정

  • AMQP메시지 기반 통신의 프로토콜이고, RabbitMQ는 이 프로토콜을 따르는 메시지 브로커를 의미한다.
  • ⭐️ 분산 처리 과정
    1) Producer -> Broker(RabbitMQ) : Procuder가 "메시지 생성"하여 Broker로 "송신"한다.
    2) Broker -> Exchanges : 메시지를 받은 Broker는 "Exchanges의 라우팅 알고리즘"을 통해 메시지를 적절한 "큐에 전달"한다.
    3) Binding : "Exchang와 Queue의 관계"를 설정하여 연결할 때 전달 규칙(라우팅)을 정한다.
    4) Exchanges -> Queue : Binding된 "Queue에서는 메시지를 저장"하여 안정적인 비동기 통신을 처리한다.
    5) Queue -> Consumer : Queue에 저장된 메시지를 Consumer에게 전달한다.
    6) Consumer -> Broker : "Consumer가 메시지를 처리가 완료"되면 "Broker에게 완료 신호"를 보낸다.
    7) Broker -> Producer : 전송받은 완료 신호를 "Producer에게 전달"한다.
    8) Broker : 처리가 "완료된 메시지를 큐에서 삭제"한다.

3. 🤔Why Stomp + RabbitMQ?

Stomp에서는 메시지를 받아서 RabbitMQ에 전달만 해주는 역할을 한다.
그렇다면 왜 Server -> RabbitMQ로 가도록 구성하지 않고, Stomp를 중간에 사용해서 Server -> Stomp -> RabbitMQ로 가는걸까?

1) STOMP와 RabbitMQ의 역할

  • Stomp ( Client <-> Server) = 클라이언트와 서버간의 "실시간 통신"에 사용된다.
  • RabbitMQ ( Server <-> RabbitMQ) =

2) Stomp가 추가되었을 때의 장점

  • 클라이언트 호환성
    => Stomp는 텍스트 기반의 프로토콜로, 다양한 클라이언트와 쉽게 통신할 수 있다.
    => 여러 언어와 플랫폼에서 사용 가능하기 때문에, Stomp를 사용하여 통신하는 것이 더 수월하다.
  • 프로토콜 변환 오버헤드 감소
    => 클라이언트와 서버 간의 통신이 단순해져서, 구현하기 쉽다.
    => STOMP를 사용하면, 사용자가 보낸 메시지 그대로 RabbitMQ로 보낼 수 있기 때문에, 서버가 메시지를 변환할 필요 X
    (변환 과정에서 발생하는 오버헤드 감소)

4. 🗣️서비스 측면 고려해보기

⭐️ Ping/Pong 적용

  • 사용자가 오랜 시간 동안 휴대폰을 켜두기만 한다면?
    => 소켓 연결시에는 OS 레벨의 리소스를 사용하며, "일정 시간 동안 활동이 없는 소켓을 자동으로 정리"한다.
    => 사용자가 핸드폰을 켜두기만 하여도, 계속 서비스가 유지가 되어야 한다.
  • 고려사항
    => 사용자가 화면을 보지 않고, 방치해두어도 메시지는 실시간으로 업데이터 되어야한다.
    => 앱이 백그라운드로 전환되었어도 메시지를 받을 수 있어야한다.
  • ⭐️ Ping/Pong 사용
    => 클라이언트가 주기적으로 서버에 작은 크기의 PING 메시지를 보내야한다. (ex. 30초마다)
    => 서버는 PING을 받으면 즉시 PONG으로 응답한다.
    => 이 과정에서 양뱡향 연결을 확인하고, 연결에 문제 발견시 재 연결을 시도한다.
    ( 재 연결시 지수 백오프(exponential backoff) 전략을 사용하면 서부 부하 줄일 수 있다.)

⭐️ 채팅 DB 구조

  • 단체 채팅방이 존재하는 경우 발생 가능 문제 사항
    => 단체 채팅방 내부의 메시지를 찾기 위해서는 채팅방ID를 찾아서 그 내부 메시지를 검색해야한다.
    => 이러한 요청이 많고, 채팅방, 채팅의 수가 늘어나면 연산이 많아 질 수도 있다.
  • PK를 Message_Id와 chatRoom_Id를 복합키로 저장해보자!
    => 위와 동일하게 Message 테이블에 채팅방Id도 복합키로 설정한다면 데이터 분산, 빠른 조회, 확장성, 병렬 처리, 효율적인 인덱싱 처리 등이 가능해진다.

⭐️ 대규모 서비스 시 Queue 관리 법 (추가 고려 후 정리 예정)

  • 소규모(500명이하) 서비스에서의 채팅 흐름
    => 사용자마다 개인의 큐를 확인하여 채팅을 처리한다.
    => 채팅방 내에 있는 많은 사람들에게 보내기 위해, 메시지를 수신자별로 복사해서 큐에 넣는 작업을 진행한다. ( 복사해서 큐에 넣는것은 비용이 크게 들지 X)
  • 대규모 서비스에서 고려해야할 흐름 (추가 고려 후 정리 예정)
    => 메시지 중앙 저장소
    => DB 분산화 & 샤딩 & 인덱싱
    => 적절한 Worker 수

⭐️ 메세지 캐싱 전략

  • 메시지 조회 속도를 위한 개선 사항이 있을까?
    => 클라이언트가 이미 읽은 메시지를 캐시해주면, 서버와 주고받는 데이터 양을 줄일 수있다.
    => 이 경우는 Redis를 사용해서 구현할 수 있을 것 같지만, TTL이나 주기는 추가적으로 더 고려해봐야 할거같다

5. RabbitMQ 구현 과정

1. application.yml 파일 설정

rabbitMQ를 설정할 때, 개방해야 하는 포트가 여러 개이다.

  • 5672: Server가 RabbitMQ에 연결할 때 필요한 port
  • 15672: RabbitMQ 관리자 UI에 접근하기 위한 port
  • 61613: STOMP 통신을 위해 필요한 port
    - 공식 문서에서 특별한 설정이 없다면, STOMP 어댑터는 61613 port를 listen 한다고 나와있다.

+) vhost 설정은 채팅 기능 이외에 다른 목적으로 RabbitMQ를 사용할 일이 있다면, vhost로 구분하여 사용할 수 있다.


참조 블로그
1. https://dev-gorany.tistory.com/325
2. https://adjh54.tistory.com/284

profile
매일매일 차근차근 나아가보는 개발일기

0개의 댓글