개요

채팅 메세지를 보내면 RabbitMQ로 메세지 전송 후 MongoDB에 해당 메세지 백업 후 MySQL에 마지막으로 보낸 메세지와 날짜를 업데이트 한다.

이 3가지의 과정이 동기적으로 일어나므로, 이 또한 부하를 줄 수 있을 것으로 판단되어 비동기처리를 적용한다.

현재 RabbitMQ라는 메세지 큐를 사용하고 있기 때문에 비동기처리가 가능하다.

핵심 시나리오별 데이터 흐름

A. 채팅방 입장 및 과거 메시지 조회 (PULL)

  1. 클라이언트: 채팅방 목록에서 특정 방을 클릭한다.
  2. API 요청: 클라이언트는 서버에 GET /api/v1/chat/rooms/{roomId}/messages 요청을 보낸다. (스크롤을 올릴 경우 ?lastMessageTimestamp=... 포함)
  3. ChatMessageController: 요청을 받아 ChatMessageReader(Service)를 호출한다.
  4. ChatMessageRepository: (roomId, timestamp) 복합 인덱스를 사용하여 MongoDB에서 과거 메시지를 효율적으로 조회(페이지네이션)한다.
  5. 응답: 조회된 과거 메시지 목록이 클라이언트로 반환되고, 화면에 표시된다.
  6. 웹소켓 구독: 클라이언트는 해당 roomId에 대한 웹소켓 구독(subscribe)을 시작하여 실시간 메시지를 받을 준비 한다.

B. 메시지 전송 및 실시간 수신 (PUSH & 비동기 저장)

실시간 전달영구 저장이 두 개의 경로로 나뉘어 동시에 처리된다.

[클라이언트 A] --(WebSocket SEND)--> [ChatController]
                                             |
                                             | (1. 메시지 발행)
                                             V
                                     [RabbitMQ Exchange]
                                             |
         +-----------------------------------+-----------------------------------+
         |                                                                       |
         V (경로 A: 실시간 전달)                                                   V (경로 B: 비동기 저장)
 [ChatMessageConsumer] --(2)--> [STOMP Broker]                             [ChatMessageBackupConsumer]
         |                                                                       |
         | (3. 실시간 방송)                                                          | (4. 백그라운드 작업)
         V                                                                       V
 [구독중인 모든 클라이언트 (A, B)]                                            [MongoDB 저장 & RDBMS 업데이트]
  1. 메시지 발행: ChatControllerfindOrCreateRoom으로 roomId를 확정한 뒤, 받은 메시지를 RabbitMQ Exchange로 즉시 발행하고 자신의 역할을 마친다.
  2. 경로 A (실시간): ChatMessageConsumer가 메시지를 즉시 받아 STOMP 브로커를 통해 해당 roomId를 구독 중인 모든 클라이언트(A와 B 모두)에게 전달한다.