Dev Projects

[table-now] 1:1(예약자:가게) 채팅 기능 고도화를 위해 RabbitMQ Relay를 적용한 이유

기만나🐸 2025. 6. 5. 16:57

🔍 개요

TableNow의 1:1 채팅 기능은 예약자와 가게 사장이 실시간으로 원활하게 소통할 수 있도록 제공된 기능이다.

초기에는 Spring의 SimpleBroker를 사용해 간단하게 구현되었지만, 멀티 인스턴스 환경에서 채팅 메시지가 공유되지 않는 문제점이 있었다.

이에 따라 RabbitMQ를 도입하고, STOMP Relay 구조로 전환함으로써 실시간성과 확장성을 확보하고자 했다.

이 글에서는 기존 구조의 한계와 개선 이유, 그리고 RabbitMQ Relay 구조를 선택하게 된 배경과 테스트 결과를 정리한다.

 


⚠️ 기본 채팅 구조의 한계 - SimpleBroker의 구조적 문제점

Spring의 기본 메시지 브로커인 `SimpleBroker`는 다음과 같은 한계를 가지고 있었다:

  • 단일 서버 메모리 기반
    • 메시지가 Spring 서버 메모리에 저장되어, 서버 인스턴스 간 메시지 공유 불가능
  • 확장성 부족
    • 서버가 늘어나도 각 서버가 개별적으로 메시지를 처리 → 멀티 인스턴스 대응 불가
  • 실시간성의 한계
    • 브로드캐스트를 WebSocket 서버가 직접 처리 → 부하 집중지연 발생 가능성

이로 인해 서버를 2개 이상 실행하는 경우, 서로 다른 인스턴스 간에는 채팅 메시지가 전달되지 않는 문제가 발생했다.

 


📋 요구사항

기능적 요구사항

  • 1:1 채팅의 실시간 동기화
    • 예약자와 가게 사장이 서로 다른 서버에 접속해도 실시간 메시지 수신이 가능해야 함
  • 서버 간 메시지 공유
    • WebSocket 서버 인스턴스가 여러 개일 경우에도 메시지가 중앙에서 관리되고 공유되어야 함
  • 알림 처리 분리
    • 채팅 메시지 저장과 별개로 비동기 알림(Notification) 처리가 필요함

 

비기능적 요구사항

  • 확장성 확보
    • 멀티 서버 환경에서도 문제없이 작동
  • 설정 유연성
    • 테스트 또는 환경에 따라 브로커 타입(Simple / RabbitMQ)을 선택 가능해야 함

 


📝 의사결정 및 사유

선택한 구조: `WebSocket + STOMP + RabbitMQ Relay`

 

선택 사유

  • 멀티 서버 환경에서도 채팅 메시지의 실시간 동기화가 보장되어야 했음
  • Spring WebSocket 서버는 relay만 수행, 브로커 기능은 RabbitMQ가 담당
  • RabbitMQ는 메시지 브로드캐스트 책임을 가지며, 클라이언트는 MQ를 통해 실시간 메시지 수신 가능
  • 알림(Notification)은 MQ에 발행된 메시지를 `@RabbitListener`로 수신하여 비동기 처리
  • 설정값(`chat.broker`)으로 Simple ↔ RabbitMQ 간 전환 가능하여 테스트 편의성 확보

 

개선 구조의 흐름

[Browser (WebSocket)]  
    → [Spring WebSocket (STOMP)]  
        → [RabbitMQ (TCP 61613)]  
            ↘︎                     ↗︎
             사용자 ↔︎ 구독자들에게 브로드캐스트
  • 클라이언트는 WebSocket으로 서버에 연결
  • 서버는 STOMP 메시지를 RabbitMQ로 relay
  • RabbitMQ는 `amq.topic`을 통해 클라이언트에 브로드캐스트

 

메시지 저장과 알림 처리의 분리

 

SimpleBroker vs RabbitMQ Relay

 

테스트 결과

SimpleBroker 환경

서로 다른 서버 포트(8080, 8081)에서는 메시지가 공유되지 않음

 

RabbitMQ Relay 환경

동일한 채팅방에서 서버를 넘나들며 메시지 실시간 공유 가능

→ 실제 테스트 환경에서 RabbitMQ Relay 구조는 실시간성, 안정성, 확장성 모두 충족했음을 검증함

 


✅ 결론

1:1 채팅 시스템에서 SimpleBroker는 구조적으로 확장성에 한계가 있었고, 멀티 서버 환경에서는 실질적인 실시간 동기화가 불가능했다.

이에 따라 RabbitMQ Relay 구조로 전환함으로써 다음을 실현할 수 있었다:

  • 멀티 인스턴스 환경에서의 메시지 실시간 공유
  • 채팅 메시지와 알림 처리 분리


이제 채팅 서비스는 여러 서버에서도 문제없이 작동할 수 있는 구조로 바뀌어, 사용자들이 끊김 없이 실시간으로 대화를 나눌 수 있게 되었다!

 

https://github.com/spring-team-7/table-now/pull/199

 

[feat] WebSocket + RabbitMQ 기반 채팅 기능 고도화 by mannaKim · Pull Request #199 · spring-team-7/table-now

🔗 Issue Number close #189 📝 작업 내역 Spring WebSocket + STOMP 메시지 Relay를 RabbitMQ로 전환 이전 구조 (SimpleBroker)에서는 → 서버(Spring)가 직접 클라이언트에게 메시지를 브로드캐스트 지금 구조 (StompBrok

github.com