WebSocket STOMP 프로토콜 구조와 실무 도입 포인트
핵심 요약 STOMP은 WebSocket 위에서 동작하는 텍스트 기반 메시징 프로토콜로, 발행-구독 구조와 프레임 규격을 제공한다. 프레임 명령, 브로커 선택, 하트비트와 재연결, 권한 설계까지 실무에서 짚어야 할 지점을 정리했다.
WebSocket STOMP란 무엇인가
STOMP은 WebSocket 연결 위에서 동작하는 텍스트 기반 메시징 프로토콜이다. STOMP 공식 문서에 따르면 이 프로토콜은 단순함과 상호운용성을 목표로 설계돼, 언어나 플랫폼에 관계없이 어떤 STOMP 클라이언트든 지원 브로커와 통신할 수 있는 공통 와이어 포맷을 제공한다. WebSocket 자체는 브라우저와 서버 사이에 양방향 통신 채널만 열어줄 뿐, 그 위로 어떤 형식의 데이터를 주고받을지는 정하지 않는다. STOMP은 이 빈자리에 발행-구독 구조와 메시지 형식을 얹어, 실시간 기능을 규칙 있는 방식으로 다루게 해준다. 채팅, 알림, 실시간 대시보드처럼 서버가 특정 클라이언트에게 메시지를 먼저 밀어 넣어야 하는 화면에서 주로 선택된다.
이름은 Simple(또는 Streaming) Text Oriented Messaging Protocol의 약자로 알려져 있다. 이름 그대로 사람이 눈으로 읽을 수 있는 텍스트 프레임을 쓰기 때문에, 개발 중에 오가는 메시지를 그대로 로그로 찍어 확인하기 편하다는 점이 실무에서 큰 장점이다. 바이너리 프로토콜과 달리 별도 디코딩 없이 흐름을 따라갈 수 있다.
WebSocket만 쓰면 안 되나
가능하지만, 규모가 커질수록 직접 만들어야 하는 것이 많아진다. 순수 WebSocket으로 실시간 기능을 짜면 메시지 종류를 구분하는 규칙, 특정 사용자에게만 보내는 라우팅, 구독 관리를 전부 손으로 설계해야 한다. 처음에는 간단해 보여도 채널이 늘고 대상이 세분화되면 이 부분 자체가 하나의 사설 프로토콜로 커진다.
STOMP은 이 공통 작업을 표준 형태로 미리 정해둔다. 클라이언트는 목적지(destination)를 구독하고, 서버나 다른 클라이언트는 그 목적지로 메시지를 보낸다. 브로커가 구독자 목록을 관리하며 해당 목적지로 온 메시지를 구독자에게 전달한다. 덕분에 누가 무엇을 구독했고 어디로 보내는지를 매번 새로 설계하지 않아도 된다. 팀이 바뀌어도 같은 규약을 공유하니 인수인계 비용도 줄어든다.
프레임 구조는 어떻게 생겼나
STOMP 메시지는 HTTP 요청과 닮은 프레임 단위로 오간다. 각 프레임은 명령(command) 한 줄, 여러 줄의 헤더, 빈 줄, 그리고 본문으로 이루어진다. 구조가 텍스트라서 처음 접해도 눈으로 흐름을 따라가기 쉽다.
자주 쓰는 명령은 다음과 같다.
- CONNECT / CONNECTED: 클라이언트가 세션을 열고 서버가 응답하는 단계
- SUBSCRIBE / UNSUBSCRIBE: 특정 목적지 구독을 시작하거나 해제
- SEND: 목적지로 메시지를 발행
- MESSAGE: 브로커가 구독자에게 메시지를 전달
- ACK / NACK: 메시지 수신 확인 또는 거부
- DISCONNECT: 세션 종료
헤더에는 목적지, 콘텐츠 타입, 메시지 식별자 같은 정보가 들어간다. 본문 형식에는 제약이 없어 JSON을 실어 보내는 경우가 많다. 수신 확인이 필요한 메시지에는 ACK 헤더를 붙여 브로커가 재전송 여부를 판단하도록 맡기는 방식도 쓰인다.
실무에서 어디에 주의해야 하나
가장 먼저 부딪히는 선택은 브로커다. 스프링 공식 문서에 따르면 간단한 용도로는 애플리케이션에 내장된 메시지 브로커를 쓸 수 있고, 대규모 트래픽이나 메시지 영속성이 필요하면 RabbitMQ나 ActiveMQ 같은 외부 브로커를 연동하도록 안내된다. 초기에는 내장 브로커로 시작하고 부하가 커지면 외부 브로커로 옮기는 흐름이 흔하다.
연결 유지도 놓치기 쉽다. 네트워크 중간의 프록시나 로드밸런서가 유휴 연결을 끊어버리는 경우가 있어, STOMP의 하트비트(heartbeat) 설정으로 양쪽이 주기적으로 신호를 주고받게 해두는 편이 안전하다. 연결이 끊겼을 때 클라이언트가 자동으로 재연결하고 이전 구독을 복구하는 로직도 처음부터 넣어두는 것이 좋다. 이 부분을 미루면 배포 직후 재접속 폭주로 장애가 번지기 쉽다.
보안은 두 층위로 나눠 본다. 연결 시점의 인증은 CONNECT 프레임 헤더에 토큰을 실어 검증하는 방식이 자주 쓰이고, 그 뒤에는 어떤 사용자가 어떤 목적지를 구독하거나 발행할 수 있는지 권한을 따로 통제해야 한다. 목적지 이름을 설계할 때 사용자별 개인 채널과 공용 채널을 구분해두면 이 권한 관리가 한결 수월해진다.
정리하며
STOMP은 WebSocket이라는 낮은 층의 연결 위에 발행-구독이라는 익숙한 그림을 얹어주는 얇은 규약이다. 실시간 기능을 처음부터 직접 설계하는 대신 검증된 메시징 패턴을 빌려 쓰고 싶을 때, 특히 스프링 생태계에서 개발한다면 후보로 검토해볼 만하다. 다만 브로커 선택과 연결 복구, 권한 설계는 프레임워크가 대신 해주지 않으므로, 트래픽 특성과 보안 요구사항을 먼저 그려본 뒤 도입하는 편이 좋다.