저번에 알아본 WebSocket 기술 보다 STOMP를 사용하는 것이 더 좋다는 얘기를 듣고 이 둘의 차이점과 왜 STOMP를 사용해야 좋은지 알아보기로 했다.
먼저 WebSocket 기술만 사용했을 때의 단점을 알아보자. 우선 기본적인 WebSocket은 낮은 수준의 프로토콜로 제공하는 기능이 제한적이다.(구현할 것들이 많다) 또한 Websocket Session 관리도 따로 되지 않아 따로 관리를 해야한다. 이런 관리와 더불어 전송을 알아서 해주지 않기 때문에 메시지 전송에 대한 추가 작업이 필요하다.(메시지 처리) 만약 클라이언트에서 Websocket 지원을 안할 경우 방법이 없지만 STOMP는 Long Polling 등으로 대체가 가능하다.(연결관리) 낮은 라우팅 기능 부실한 인증 기능 또한 문제가 되고 있다.
밑의 코드는 WebSocket에서 Session을 저장해놓고 send를 보내주는 코드이다.
for(WebSocketSession webSocketSession : sessions) {
if(webSocketSession.isOpen()) {
webSocketSession.sendMessage(messageToSend);
}
}
이는 WebSocket Session 을 저장하고 있다가 for - loop 문으로 일일이 send를 보내주는 형태이다. 만약 연결하고 있는 세션의 수가 많아지면 for loop(동기적) 지연 발생 가능성이 높아진다. 마지막으로 WebSocket은 단순히 데이터를 주고받는 통신 방식을 제공하고 (전화기 역할) 어떤 형식으로 메시지를 주고받을지에 대한 규격이 없다. 하지만 STOMP는 메시지 형식을 정해주는 프로토콜이다. (대화를 위한 공통 언어)
예를 들어,
- WebSocket만 있으면, 전화기만 있는 상황이다.
- 전화기를 걸었는데, 상대방이 내 말을 이해할 수 있을지 장담할 수 없으며 내가 한국어를 말하는데, 상대방이 영어만 이해하면 소통이 안된다. 이러면 메시지를 보낼 수는 있지만, 구조가 없어서 메시지 해석이 어렵다.
- 하지만 STOMP를 사용하면, 대화를 위한 공통 언어를 정할 수 있다.
- 내가 한국어를 쓰고, 상대방도 한국어를 쓰도록 규칙을 정하면 의사소통이 원활해지며, 메시지를 어떤 형식으로 주고받을지 표준화할 수 있다. 즉, STOMP를 사용하면 메시지를 목적지(destination) 기반으로 분류하고 관리할 수 있다.
WebSocket만 사용했을 때의 단점만 알아보아도 이대로 사용하면 안된다는 생각이 든다. 이제 STOMP가 어떤 점에서 WebSocket 보다 뛰어난지 자세히 알아보자.
STOMP는 웹 소켓 위에서 동작하는 메시지 프로토콜로 메시징 시스템 간에 데이터를 교환하기 위한 간단하면서도 유연한 텍스트 기반 프로토콜이다. 웹 소켓 기반으로 동작하며, 메시징 애플리케이션에서 표준 프로토콜로 채택되어 있다. 이는
1. Pub/Sub( Publish-Subscribe ) 구조 : 메시지를 공급하는 주체와 소비하는 주체를 분리해 제공하는 메시징 방법이다.

이는 발행자(Publisher)가 특정 토픽이나 큐에 메시지를 생성하고 발행하면 메시지 브로커가 발행된 메시지를 관리하여 특정 주제나 큐에 구독한 구독자(Subscriber)들에게 메시지를 전달하는 방식이다.
2. 메시지 중심으로 읽기 편하고 단순하다.
3. 메시지 브로커와의 호환 성이 좋아 RabbitMQ 등 메시지 브로커와 쉽게 통합되어, 분산 메시징 구축에 유리하다.
이런 특징을 가지고 있고,

위 그림은 대표적인 STOMP 프로토콜의 메시지 전달 방식이다. STOMP 메시지는 3가지 주요 채널(Request Channel, Broker Channel, Response Channel)을 통해서 전달된다. 먼저 클라이언트가 메시지를 전송하면, Request Channel 응답 채널에서 /app 혹은 /topic 목적지로 메시지를 전달 후 결과를 반환한다. /app으로 간 메시지는 SimpAnnotationMethod에서 Controller로 추가 작업을 거친 후에 broker channel에서 /topic 주소로 전달되어 실제 클라이언트 세션을 관리하고 전송하는 SimpleBroker로 이동하고, 이 메세지 브로커가 메세지를 response channel(응답 채널)로 전송하여 이 채널을 구독하고 있는 구독자들에게 전달한다.
결론은
✅ /app은 컨트롤러에서 메시지를 처리하는 목적지
✅ /topic은 브로커에서 메시지를 클라이언트에게 전달하는 목적지
✅ STOMP 메시지는 Request Channel → Broker Channel → Response Channel을 거쳐 전달됨
즉, STOMP를 사용하면 컨트롤러에서 메시지를 가공한 후, 브로커를 통해 여러 클라이언트에게 쉽게 메시지를 전달할 수 있다.
이를 스프링에서 사용한다면,
- RabbitMQ, ActiveMQ 같은 Message Broker을 이용해서, subscription을 관리하고 메시지를 브로드캐스팅할 수 있다.
- WebSocket 기반으로 각 커넥션마다 WebSocketHandler를 구현하는 것보다, @Controller된 객체를 이용해서 조직적으로 관리할 수 있다.
- 즉 메시지들은 STOMP의 Destination 헤더를 기반으로, @Controller 객체의 @MethodMapping 메서드로 라우팅된다.
- STOMP의 Destination 및 Message Type을 기반으로 메시지를 보호하기 위해, Spring Security를 사용할 수 있다.
STOMP의 Frame은 몇 개의 텍스트 라인으로 지정된 구조인데
COMMAND
header1:value1
header2:value2
Body^@
첫번째 라인은 텍스트(Command 명령어)이고 이후 key:value 형태로 header 정보를 포함한다. header이후에 공백 줄을 하나 더 추가하는 것으로 header의 끝을 설정할 수 있다.
header이후에는 Payload(Body)가 존재한다.
페이로드(Payload)는 전송되는 데이터를 의미.
[EX] JSON에서 DATA 부분.
[EX] 택배 배송을 보내고 받을 때, 택배 물건이 payload.
COMMAND에 사용 가능한 명령어들은 아래와 같고 상세 구현 내용은 STOMP 공식 페이지에서 확인 할 수 있다.
- CONNECT
- SEND
- SUBSCRIBE
- UNSUBSCRIBE
- BEGIN
- COMMIT
- ABORT
- ACK
- NACK
- DISCONNECT
마지막으로 STOMP를 정리하면서, 하나 더 배운 것이 있는데 바로 SockJS이다. 간단하게 정리해보자면 이것의 목표는 WebSocketAPI를 사용할 수 없게 된 경우 코드 변경없이 WebSocket 이외의 대안으로 대체해준다. 특징으로는 브라우저에서 사용하도록 설계가 되었기 때문에, 다양한 브라우저와 버전을 지원하고 있다.
또한 SockJS는 WebSocket, HTTP Streaming, HTTP Long Polling 등의 크게 세 가지 전송 방법(Transports)을 지원하고 있는데, 이외에도 아래와 같이 다양한 방식을 제공하고 있다.

'개발 공부' 카테고리의 다른 글
| Elasticsearch써보자(1) (0) | 2025.04.10 |
|---|---|
| TPS(Transaction Per Second) (0) | 2025.03.28 |
| WebSocket 통신 방식이란? (0) | 2025.03.26 |
| 코딩테스트와 알고리즘 연습 (0) | 2024.11.28 |
| CORS가 뭐지 (0) | 2024.11.08 |