백엔드 면접 용어 사전
API·RESTSimple Text Oriented Messaging Protocol

STOMP

raw WebSocket 위에 목적지·구독 개념을 얹는 텍스트 메시징 규약. 채팅방처럼 구독 단위가 여럿일 때 쓴다.

WebSocket 위에 얹는 간단한 텍스트 기반 메시징 프로토콜(서브프로토콜).

왜 필요한가 — WebSocket에는 개념이 없다

WebSocket은 바이트를 주고받는 통로일 뿐이다. 규격에 있는 건 프레임과 텍스트/바이너리 구분뿐이고, 그 안에 무엇을 담을지는 정해져 있지 않다.

채팅방이 여러 개인 서비스
  이 메시지는 어느 방 것인가?      → 직접 정의해야 한다
  누가 어느 방을 구독 중인가?      → 직접 관리해야 한다
  구독 해제는 어떻게 표현하나?     → 직접 정의해야 한다

결국 각 팀이 {"type":"subscribe","room":"..."} 같은 규약을 매번 새로 만들게 된다. STOMP는 그 규약을 표준화한 것이다.

프레임 구조 — HTTP를 닮았다

SEND
destination:/app/chat
content-type:application/json

{"text":"안녕하세요"}
^@                         ← NULL 바이트로 프레임 종료

명령 + 헤더들 + 빈 줄 + 본문이라는 모양이 HTTP와 같아서 읽기 쉽다. 주요 명령은 이렇다.

명령
CONNECT / CONNECTED세션 시작
SUBSCRIBE / UNSUBSCRIBE목적지 구독·해제
SEND목적지로 메시지 발행
MESSAGE서버가 구독자에게 전달
ACK / NACK수신 확인·거부

목적지 규칙이 핵심이다

  • /topic/... — 브로드캐스트 — 구독자 전원에게 (채팅방·공지)
  • /queue/... — 1:1 — 특정 사용자에게 (개인 알림)
  • /app/... — 서버 측 처리 로직으로 라우팅 (메시지를 가공해 다시 발행)

이 관례 덕분에 "어디로 보내고 어디를 구독한다" 가 문자열 하나로 표현되고, 구독 관리를 프레임워크나 브로커에 맡길 수 있다.

언제 쓰고 언제 안 쓰나

구독 단위가 여럿 (채팅방·종목별 시세·문서별 협업)

  • STOMP 가 수고를 덜어 준다

연결 하나에 단순한 메시지 한 종류 (진행률·알림 스트림)

  • raw WebSocket 이나 SSE 로 충분. STOMP는 오버헤드

스케일아웃에서 주의

STOMP를 쓰더라도 연결이 인스턴스에 묶인다는 사실은 그대로다. 내장 메모리 브로커만 쓰면 한 인스턴스에 붙은 구독자에게만 메시지가 닿는다. 여러 대로 늘리려면 외부 브로커를 붙여 모든 인스턴스가 같은 브로커를 공유해야 한다.

채널과 인터셉터 — 인가를 어디에 거는가

  • 핸드셰이크(HTTP) — 필터 체인을 탄다 → 여기서 인증한다
  • STOMP 프레임 — 필터를 거치지 않는다 → ChannelInterceptor 로 검사한다

특히 SUBSCRIBE 를 검사하지 않으면 /topic/room.{id} 처럼 목적지에 식별자가 들어갈 때 남의 방을 구독하는 구멍이 그대로 열린다

면접에서 "WebSocket 인증은 어떻게 하나요" 를 물으면 이 두 단계를 나눠 답하는 것이 정답에 가깝다

여러 인스턴스로 늘릴 때 무엇이 깨지나

  • 내장 SimpleBroker — 구독 정보가 그 인스턴스 메모리에 있다

    • 파드를 2개로 늘린 순간 '메시지가 절반만 온다'
  • 외부 브로커 릴레이 — 모든 노드가 같은 브로커를 공유해 팬아웃이 전 노드에 닿는다

    • RabbitMQ 는 STOMP 플러그인이 필요하다
  • 사용자별 전송 — convertAndSendToUser 는 노드마다 다른 레지스트리를 본다

    • 레지스트리·목적지 브로드캐스트를 켜거나,
      • 구독 키를 도메인 식별자로 바꾼다

배포와 재연결

연결이 상태를 갖기 때문에 배포는 곧 전면 재연결이다

  • 클라이언트에 지수 백오프 + 지터가 없으면 재연결 폭주로 새 파드가 무너진다
  • 끊긴 사이의 메시지는 사라진다 → 재연결 후 커서로 따라잡는 경로가 필요하다
  • 하트비트를 켜지 않으면 중간 장비가 유휴 연결을 조용히 끊는다

"실시간 푸시" 와 "전달 보장" 은 다른 문제다 — 중요한 알림은 푸시와 별개로 조회 API 를 둔다

언제 쓰지 않나

  • 서버→클라이언트 단방향이면 SSE 가 더 싸고 단순하다

  • 메시지 종류가 한두 개면 raw WebSocket 으로 충분하다

  • 이미 자체 프로토콜이 있으면 얹을 이유가 없다

  • STOMP 가 값을 하는 자리는 '목적지가 여럿이고 구독 관리가 필요할 때' 다

면접 함정

  • "STOMP는 WebSocket의 대체재" → WebSocket 위에 얹는 층이다.
  • "STOMP를 쓰면 스케일아웃이 해결된다" → 구독 관리가 편해질 뿐, 인스턴스 간 전달은 여전히 외부 브로커의 몫이다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — API·REST 설계 — 멱등성·상태코드·버저닝·GraphQL