9osari.log
← 목록으로

[DevBid - 실시간통신] 멀티 서버 환경에서 Redis Pub/Sub이 필요한 이유

📚 실시간 경매 시스템 구축기 시리즈

  1. WebSocket으로 실시간 경매 구현하기
  2. WebSocket 메시지 동기화 문제와 Redis 선택 ← 현재 글
  3. Redis 분산락과 Pub/Sub으로 멀티서버 동시성 제어
  4. Redis 도입 후 마주한 문제와 해결
  5. 멀티서버 환경에서 Pub/Sub와 분산락 검증

현재 구현의 한계

현재는 단일 서버 환경에서 Spring@EventListenerWebSocket 을 조합해서 실시간 입찰과 즉시구매 동기화를 구현했습니다. 지금은 완벽하게 동작하지만..

만약 서비스가 성장하면서 트래픽이 증가하면 필연적으로 멀티서버 환경을 구축해야 합니다.

왜 서버를 나눠야 할까?

Devbid 같은 경매 서비스는 특정 시간대에 트래픽이 몰리게 됩니다.

단일 서버 환경으로는 이런 순간적인 부하를 감당하기 어렵다 생각

일반적인 해결책은 서버를 여러 대로 늘리고 로드밸런서로 트래픽을 분산시키는 것

즉, 수평적 확장(Scale-out)

그런데 문제가 있다.

서버를 여러 대로 늘리는 순간, 현재의 WebSocket 구현은 작동하지 않는다…

Spring Event의 작동 방식

public class AuctionWebSocketEventListener {
    private final SimpMessagingTemplate messagingTemplate;
  
    @EventListener //인메모리 이벤트
    public void handleBidPlacedEvent(BidPlacedEvent event) {
      log.info("입찰 이벤트 수신: {}", event);
      //DTO 생성
      ...
      //같은 JVM 프로세스 내에서만 전달됨
      messagingTemplate.convertAndSend("/topic/auctions/" + event.getAuctionId(), dto);
      log.info("WebSocket 전송 이벤트 종료..");
    }
}

각 서버는 독립적인 JVM 사용


실제로 벌어질 상황

[서버 A - 8080포트]          [서버 B - 8081포트]
  ├─ 유저1 (WebSocket 연결)    ├─ 유저2 (WebSocket 연결)
  ├─ 유저3 (WebSocket 연결)    ├─ 유저4 (WebSocket 연결)
  └─ 유저5 (WebSocket 연결)    └─ 유저6 (WebSocket 연결)

시나리오: 유저1이 “맥북” 경매에 100만원 입찰

1. 유저1 → 서버A: "100만원 입찰!"

2. 서버A: 입찰 처리 완료

3. 서버A: BidPlacedEvent 발행 (서버A의 메모리에만 존재)

4. 서버A: @EventListener가 이벤트 수신

5. 서버A: WebSocket으로 전송
   ├─ 유저1 "100만원 입찰됨!" 받음
   ├─ 유저3 "100만원 입찰됨!" 받음
   └─ 유저5 "100만원 입찰됨!" 받음

   서버B는
   ├─ 유저2 아무것도 모름 (여전히 95만원으로 보임)
   ├─ 유저4 아무것도 모름
   └─ 유저6 아무것도 모름

이게 왜 심각한 문제인가?

14:00:01 - 유저1이 100만원 입찰 (서버A에서 처리)
         - 서버A 유저들: 100만원으로 갱신
         - 서버B 유저들: 여전히 95만원으로 보임

14:00:05 - 유저2 (서버B): "95만원이네? 100만원 입찰!"
         → DB: "현재가가 이미 100만원인데?" 
         → 입찰 실패

서버 증설의 의미 퇴색

서버를 아무리 늘려도, 각 서버가 독립적으로 동작하면서 서버 간에 알림이나 이벤트 정보를 공유하지 못하면 문제가 발생합니다.

이 때문에 한 서버에서 처리된 알림이 다른 서버에 전달되지 않아 일부 유저는 실시간 알림을 전혀 받지 못하게 됩니다.


메시지 브로커

여러 서버가 공통으로 메시지를 주고받을 수 있는 중앙 메시지 브로커가 필요합니다.

이를 구현하는 방식은 여러 가지가 있습니다.

Message Queue (RabbitMQ, Kafka)

서버A → RabbitMQ → 서버B, C, D

장점

단점

언제 사용?

Database Polling

모든 서버가 주기적으로 DB 조회 -> 새로운 입찰 있으면 WebSocket 전송

장점

단점

Redis Pub/Sub

서버A -> Redis -> 서버B, C, D

장점

단점


DevBid는 Redis Pub/Sub을 선택했습니다.

경매 입찰, 즉시구매 등 실시간 알림의 특성을 고려하면

실시간 알림이라는 핵심 요구사항과 멀티 서버 확장성을 고려했을 때, Redis Pub/Sub이 가장 적합한 선택이라고 판단했습니다.


향후 확장 가능성

Redis Pub/Sub 인프라를 구축해두면 다른 실시간 기능도 쉽게 추가할 수 있습니다.

실시간 채팅 (경매 Q&A)
→ Channel: "chat:room:{roomId}"
→ 채팅방별로 메시지 격리 전달

사용자별 알림 (입찰 성공/실패, 낙찰)
→ Channel: "notifications:user:{userId}"
→ 개인화된 알림 푸시

경매 상태 변경 (종료, 연장)
→ Channel: "auction:status:{auctionId}"

메시지 영속성이 필요하면?

서비스가 성장하며 채팅 이력 보관, 알림 재전송 등의 요구사항이 생길 수 있습니다. 그때는

현재는 Redis Pub/Sub만으로 충분하지만, 아키텍쳐 설계 시 항상 확장 가능성을 염두해 두는 것이 중요하다 생각됩니다.

다음 단계

이제 실제로 Redis Pub/Sub를 DevBid에 어떻게 적용했는지 구현 과정과 발생한 문제들을 다음 포스팅에서 확인할 수 있습니다.

···
← PREV [DevBid - 실시간통신] WebSocket으로 실시간 경매 구현하기 NEXT → [DevBid - 실시간통신] Redis 분산락과 Pub/Sub 으로 멀티서버 동시성 제어