현대 웹 애플리케이션에서는 사용자 경험을 향상시키기 위해 실시간 데이터 통신이 필수적입니다. 웹 소켓, R 소켓, STOMP는 이러한 실시간 통신을 구현하는 데 널리 사용되는 프로토콜입니다. 이번 글에서는 이 세 가지 기술의 특징, 사용 사례, 그리고 스프링부트 환경에서의 적용 방법에 대해 알아보겠습니다.
⭐ 웹 소켓 (WebSocket)
✅ 왜 쓰는가?
웹 소켓은 클라이언트와 서버 간의 양방향 통신을 지원하는 프로토콜입니다.
HTTP 프로토콜은 요청-응답 방식으로 동작하지만, 웹 소켓은 한 번 연결이 이루어진 후에는 지속적인 연결을 유지할 수 있어 효율적인 데이터 전송이 가능합니다.
✅ 언제 쓰는가?
- 실시간 채팅 애플리케이션
- 실시간 게임
- 주식 거래 애플리케이션
- IoT 기기와의 통신
✅ 어떻게 쓰는가?
1. 의존성 추가하기
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
pom.xml에 웹 소켓 의존성을 추가합니다.
2. 웹 소켓 설정하기
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*");
}
}
3. 핸들러 구현하기
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class MyWebSocketHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// 메시지 처리 로직
}
}
⭐ R 소켓
✅ 왜 쓰는가?
R 소켓은 복잡한 데이터 흐름과 다양한 통신 패턴을 지원하는 프로토콜입니다.
요청-응답과 같이 클라이언트가 교청을 보내고 서버가 응답하는 전통적인 패턴은 물론, 클라이언트와 서버 간에 지속적으로 데이터를 주고 받는 방식인 스트리밍 패턴 또한 지원합니다. 예를 들어, 실시간 비디오 스트리밍이나 IoT 센서 데이터 전송에 적합합니다. 뿐만아니라 요청을 보낸 후 즉시 다른 작업을 수행하고, 서버에서 응답이 올 때까지 기다리지 않아도 되는 비동기 처리 방식 또한 당연히 지원합니다.
네트워크 지연이 느리거나 불안정한 환경에서도 효율적으로 동작합니다. 예를 들어, 원거리 서버와 통신할 때 유용합니다.
R 소켓은 TCP, WebSocket 등 여러 전송 계층에서 사용할 수 있습니다.
✅ 언제 쓰는가?
- 마이크로서비스 간 통신
- 스트리밍 데이터 처리
- 고성능 애플리케이션
✅ 어떻게 쓰는가?
1. 의존성 추가하기
<dependency>
<groupId>io.rsocket</groupId>
<artifactId>rsocket-core</artifactId>
</dependency>
pom.xml에 R 소켓 의존성을 추가합니다.
2. R 소켓 서버 설정하기
import io.rsocket.RSocketFactory;
import io.rsocket.transport.netty.server.TcpServerTransport;
public class RSocketServer {
public static void main(String[] args) {
RSocketFactory.receive()
.acceptor((setup, sendingSocket) -> Mono.just(new MyRSocketHandler()))
.transport(TcpServerTransport.create("localhost", 7000))
.start()
.block();
}
}
3. 핸들러 구현하기
import io.rsocket.RSocket;
import io.rsocket.Payload;
import reactor.core.publisher.Mono;
public class MyRSocketHandler implements RSocket {
@Override
public Mono<Payload> requestResponse(Payload payload) {
// 요청 처리 로직
}
}
⭐ STOMP(Simple Text Oriented Messaging Protocol)
✅ 왜 쓰는가?
STOMP는 메시징 프로토콜로, 주로 프론트엔드에서 사용됩니다. 즉, 프론트엔드에서 STOMP 클라이언트를 사용하여 메시지를 송수신합니다.
웹 소켓과 함께 사용하여 클라이언트와 서버 간의 메시지를 간편하게 송수신할 수 있습니다.
1. 텍스트 기반의 명확한 메시지 구조를 통해 메시지를 쉽게 읽고 이해할 수 있다.
STOMP는 메시지를 텍스트 형식으로 전달하기 때문에 메시지를 쉽게 읽고 이해할 수 있습니다. 다음과 같이 STOMP 메시지는 헤더와 본문과 같이 명확한 구조를 가지고 있기 때문에 이 구조 덕분에 메타데이터(예: 발신자, 수신자 등)를 쉽게 추가할 수 있습니다.
SEND
destination:/topic/chat
content-type:text/plain
Hello, World!
STOMP를 사용하지 않고 WebSocket만 사용할 경우, 메시지는 이진 형식으로 전송됩니다. 이 경우 메시지를 수신하려면 클라이언트와 서버 모두 이진 데이터를 처리해야 하며, 각 메시지의 형식이나 내용을 정의하는 규칙이 필요합니다. 따라서 STOMP를 쓰지 않는다면 메시지 내용과 구조를 정하는 데 더 많은 노력이 필요할 수 있습니다.
2. 구독/발행 모델
STOMP는 메시지를 송수신하는 프로토콜일 뿐만 아니라, 구독/발행 모델을 통해 특정 주제에 대한 메시지를 선택적으로 수신할 수 있도록 해줍니다.
- 구독: 클라이언트가 특정 주제(예: /topic/chat)에 대해 구독하면, 그 주제에 발행되는 모든 메시지를 수신하게 됩니다.
- 발행: 클라이언트가 메시지를 발행하면, 해당 주제에 구독하고 있는 모든 클라이언트에게 메시지가 전달됩니다.
예를 들어, 채팅 애플리케이션에서는 사용자가 특정 채팅방에 구독하고, 다른 사용자가 메시지를 보낼 때 해당 채팅방에 구독한 모든 사용자에게 메시지가 전달됩니다.
가령, 실시간 채팅 애플리케이션을 생각해보면
- 사용자가 /topic/chat에 구독합니다.
- 다른 사용자가 이 주제로 메시지를 보내면 (예: "안녕하세요!"), STOMP 프로토콜을 통해 메시지가 전송됩니다.
- 해당 주제에 구독하고 있는 모든 사용자에게 이 메시지가 전달됩니다.
이렇게 STOMP는 복잡한 프로그래밍 없이도 손쉽게 실시간 메시징을 구현할 수 있도록 해줍니다. 따라서 개발자는 비즈니스 로직에 집중할 수 있게 됩니다.
3. 유연한 연결
STOMP는 다양한 메시징 브로커와 쉽게 연동할 수 있습니다. 예를 들어, RabbitMQ, ActiveMQ와 같은 메시징 서버와의 통합이 쉬워, 복잡한 메시징 인프라를 구축할 수 있습니다.
☑️ 메시징 서버 : RabbitMQ, ActiveMQ
1. 메시징 서버란?
메시징 서버는 여러 대의 컴퓨터가 네트워크를 통해 연결되어 협력하며 작업을 수행하는 시스템을 뜻하는 분산 시스템에서 데이터와 메시지를 안전하고 효율적으로 송수신할 수 있도록 도와주는 중개자 역할을 합니다.
이들은 메시지를 큐에 저장하고, 필요할 때 적절한 클라이언트에게 전달합니다.
메시지 큐는 비동기식으로 메시지를 저장하고 전달하는 시스템입니다. 이는 주로 분산 시스템에서 사용되며, 프로세스 간의 통신을 효율적으로 처리하는 데 도움을 줍니다.
이를 통해, 여러 클라이언트 간의 통신을 간소화하고, 비동기식으로 메시지를 처리할 수 있습니다.
2. RabbitMQ & ActiveMQ
- RabbitMQ
AMQP(Advanced Message Queuing Protocol)를 사용하는 오픈 소스 메시징 브로커로, 메시지를 생산자(Producer)로부터 소비자(Consumer)에게 전달하는 역할을 하며, 주로 비동기식 메시징에 사용됩니다.
고급 라우팅 기능과 안정적인 메시지 전달을 지원합니다. 예를 들어, 메시지를 주제(Topic)나 큐(Queue)에 따라 다양한 방식으로 라우팅할 수 있고, 메시지를 디스크에 저장하여 시스템 장애 시에도 데이터 손실을 방지할 수 있습니다. 또한, 여러 프로그래밍 언어에서 사용할 수 있는 클라이언트 라이브러리를 제공합니다.
- ActiveMQ
Java 환경에서 사용하기 위해 최적화되어 있으며, JMS(Java Message Service)를 사용하는 메시징 브로커로, Java 환경에서 많이 사용합니다.
다양한 메시징 패턴을 지원하며, 다양한 클라이언트 라이브러리를 제공합니다.
3. 무엇을 선택해야할까?
- RabbitMQ를 선택해야하는 상황
- 고급 라우팅이나 다양한 프로그래밍 언어에서 사용해야하는 경우
- 많은 비동기 메시징 패턴을 요구하는 복잡한 시스템
- ActiveMQ를 선택해야하는 상황
- Java기반의 애플리케이션에서 JMS 호환성이 필요할 때
- Spring 기반의 애플리케이션에서 통합이 용이함.
✅ 언제 쓰는가?
- 채팅 애플리케이션
- 알림 시스템
- 이벤트 기반 아키텍처
✅ 어떻게 쓰는가?
1. 의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
pom.xml에 STOMP 의존성을 추가합니다.
2. STOMP 설정
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.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}
3. 컨트롤러 구현
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
private final SimpMessagingTemplate messagingTemplate;
public ChatController(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@MessageMapping("/chat")
public void sendChatMessage(String message) {
messagingTemplate.convertAndSend("/topic/messages", message);
}
}
🚩 결론
웹 소켓, R 소켓, STOMP는 각기 다른 요구 사항에 맞춰 실시간 통신을 가능하게 하는 강력한 도구입니다. 스프링부트와 함께 사용하면 더욱 쉽게 구현할 수 있으며, 다양한 애플리케이션에 적합한 솔루션을 제공할 수 있습니다. 각 기술의 특성과 적절한 사용 시기를 이해하고, 필요에 맞는 프로토콜을 선택해 실시간 애플리케이션을 개발해보세요.
'기술 지식 쌓아가기 📚 > Backend 🍔' 카테고리의 다른 글
[Spring] @Controller와 @RestController의 차이점 (0) | 2024.10.04 |
---|---|
[Cloud] MSA vs 모놀리: 당신의 프로젝트에 적합한 아키텍처는? (1) | 2024.10.03 |
[Spring] 웹 애플리케이션 테스트를 위한 Spring의 두 가지 도구: MockMvc와 WebTestClient 🍃 (0) | 2024.09.28 |
[Spring] WebFlux: 비동기와 반응형 프로그래밍의 새로운 장 🍃 (3) | 2024.09.27 |
[Spring] 안전한 웹 개발의 시작: 스프링의 Validation, Data Binding, Type Conversion 🍃 (0) | 2024.09.27 |