STOMP를 활용한 WebSocket 구현

젼이·2024년 10월 23일

WebSocket의 특징

1. 양방향 통신 (Full-duplex Communication)

  • 서버와 클라이언트 간에 실시간 양방향 통신이 가능하며, HTTP와 달리 서버도 클라이언트에 직접 푸시(push)할 수 있다.

2. 소켓 연결 유지 (Persistent Connection)

  • WebSocket은 최초의 HTTP 핸드셰이크(Handshake)로 연결을 맺은 뒤, 지속적으로 연결을 유지하면서 데이터를 주고받는다.

낮은 오버헤드 (Low Overhead)

  • 연결이 유지되므로 반복적인 요청과 응답 과정 없이 빠르게 데이터를 교환한다.

이벤트 기반

  • 서버와 클라이언트 모두 필요 시점에 이벤트를 발생시키고 데이터를 전송할 수 있어, 실시간 성능이 뛰어난다.



STOMP란 무엇인가?

STOMP (Simple Text Oriented Messaging Protocol)는 WeSocket 상위에서 동작하는 메시징 프로토콜이다. WebSocket은 단순히 소켓 연결을 제공하지만, STOMP를 사용하면 메시지 브로커와 연동하거나, 구독/발행(Publish/Subscribe) 패턴을 쉽게 구현할 수 있다.

  • 메시지 브로커 역할: RabbitMQ, ActiveMQ 등과 연동할 수 있다.
  • Pub/Sub 모델: 특정 주제(Topic)에 대한 구독을 통해 여러 클라이언트에 메시지를 전달한다.
  • ACK 처리: 메시지가 제대로 수신되었는지 확인한다.
  • 채널 기반 구독: 클라이언트는 주제(Topic)을 구독하거나 특정 사용자에게 메시지를 전송할 수 있다.



1. 구독/발행(Publish/Subscribe) 패턴이란?

이 패턴에서는 메시지 송신자(Publisher)수신자(Subscriber) 간에 직접적인 연결 없이, 주제(Topic)을 통해 메시지를 주고 받는다.

어떻게 동작하는가?

  • 발행자(Publisher): 특정 주제에 메시지를 발행한다.
  • 구독자(Subscriber): 관심 있는 주제를 구독한다.
  • 메시지 전달: 발행된 메시지는 해당 주제를 구독한 모든 구독자에게 전달된다.

예시:

  • Youtube 채널(주제)에 구독자가 있으면, 새로운 영상이 발행될 때 모든 구독자가 알림을 받는다.

구독/발행(Pub/sub) 패턴의 흐름

  1. 구독:
    클라이언트 A,B가 /topic/alerts를 구독한다고 가정한다.

  2. 발행:
    서버 또는 클라이언트 C가 /topic/alerts에 메시지를 발행한다.

  3. 알림:
    /topic/alerts를 구독한 A와 B는 실시간으로 해당 메시지를 수신한다.


    이 패턴 덕분에 클라이언트끼리의 직접 연결없이 메시지를 주고받을 수 있어, 확장성이 높아진다. 즉, 발행자가 누구인지, 몇 명인지 상관없이 주제를 통해 메시지가 전달된다.




2. 메시지 브로커(Message Broker)란?

메시지 브로커는 발행된 메시지를 중개하고 관리해 주는 역할을 하는 중앙 허브이다. 발행된 메시지를 브로커가 받아서 구독자에게 자동으로 전달해 주므로, 개발자는 발행과 구독만 신경 쓰면 된다.


메시지 브로커의 역할

  • 발행/구독 관리: 주제에 구독한 클라이언트를 관리한다.
  • 메시지 라우팅: 어떤 주제(Topic)로 발행된 메시지를 구독자에게 전달한다.
  • 비동기 메시지 전달: 메시지가 즉시 전달되지 않아도 적절한 시점에 수신된다.



주요 메시지 브로커 예시

  • RabbitMQ: 오픈 소스 메시지 브로커, 주로 메시지 큐와 Pub/Sub 패턴을 지원한다.
  • ActiveMQ: 대규모 분산 시스템에 자주 사용되는 브로커이다.
  • Kafka: 대용량의 데이터를 빠르게 처리할 수 있는 메시지 브로커이다.




3. Spring WebSocket과 STOMP에서 메시지 브로커 사용하기

Spring에서 STOMP를 사용하면 내장된 메시지 브로커를 활용하거나, 외부 메시지 브로커(RabbitMQ 등)을 연동할 수 있다. 브로커는 다음과 같은 상황에 필요하다.

  • 여러 클라이언트에게 메시지를 효율적으로 전달하기 위해 메시지 브로커가 중개한다.
  • 비동기적으로 메시지를 처리하여 서버 부하를 줄인다.

구조 예시: 메시지 브로커가 있는 STOMP의 흐름

  1. 클라이언트 A와 B는 /topic/notifications 주제를 구독한다.
  2. 서버가 /topic/notifications에 새로운 메시지를 발행한다.
  3. 메시지 브로커는 이 메시지를 받아 구독자(A,B)에게 동시에 전달한다.



4. 예시 코드: RabbitMQ 메시지 브로커와 연동

<!-- RabbitMQ 의존성 추가 (pom.xml) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 외부 메시지 브로커를 사용하는 경우
        config.enableStompBrokerRelay("/topic", "/queue")
              .setRelayHost("localhost") // RabbitMQ 서버 주소
              .setRelayPort(61613)        // RabbitMQ 포트
              .setClientLogin("guest")    // 사용자 이름
              .setClientPasscode("guest"); // 비밀번호
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS();
    }
}

정리

  • 구독/발행(Pub/Sub): 특정 주제를 기준으로 발행된 메시지가 구독한 모든 클라이언트에게 전달되는 방식이다.
  • 메시지 브로커: 발행된 메시지를 받아 구독자에게 중개해 주는 역할을 한다. 이를 통해 확장성과 비동기 메시지 처리가 가능해진다.
  • STOMP를 이용하면 WebSocket 상에서 쉽게 Pub/Sub 패턴을 구현할 수 있고, RabbitMQ 같은 외부 브로커와 연동해 더 강력한 기능을 제공할 수 있다
profile
신입 개발자 임니당 : > (2025.02.05~)

0개의 댓글