Spring WebSocket의 동작 과정

박계현·2025년 6월 11일

빨랐죠

목록 보기
3/6
post-thumbnail

들어가며

빨랐죠 GitHub
https://github.com/gyehyun-bak/ppalatjyo

Spring+React로 만든 채팅 서비스
https://github.com/gyehyun-bak/spring-react-chat-app

현재 개발 중인 <빨랐죠>의 핵심 기능 중 하나가 채팅이라 채팅 부분 개발을 하나의 오픈소스로 정리해보았습니다. 가능한 한 Spring 공식 문서를 참고하여 구현해두었습니다. Spring + React 스택으로 웹소켓 기반 채팅 서비스 개발하고 싶은 분들이 참고하기 좋도록 계속 관리할 예정입니다. 추가 이슈나 질문 등은 해당 프로젝트 리포지토리에 남겨주세요!

이번 글에서는 제가 프로젝트를 위해 웹소켓을 이용한 채팅을 구현하면서 이해한 Spring WebSocket의 동작 과정을 정리해보려고 합니다.

Spring-WebSocket

https://docs.spring.io/spring-framework/reference/web/websocket.html

Spring Framework에서 제공하는 WebSocket 패키지는 서블릿 기반 서버에서 SockJS와 STOMP를 활용한 웹소켓 애플리케이션을 만들 수 있도록 구현되어 있다고 나와있습니다.

하지만 동작 방식이 명확한 서블릿과 달리 웹소켓은 정확한 동작 방식을 이해하지 못해, 문제를 만났을 때 원인을 파악하고 해결책을 떠올리는 데 많은 어려움을 겪었습니다.

그런데 내부 아키텍처에 대해서 자세하게 설명하는 공식/비공식 문서/자료가 별로 없어서, 이 기회에 직접 패키지 내 코드를 뒤져가며 동작을 이해해보려고 했습니다.

전체 동작 과정

위와 같은 방식으로 동작을 하는 것(?) 같습니다.

WebSocket에 대한 스펙은 spring-websocket 종속성을 추가하지 않더라도, Jakarta에 기본적으로 정의된 스펙이 있고, 톰캣이 이를 구현하고 있으며 API를 제공하고 있기 때문에 직접할 수도 있습니다. WebSocketHandler를 구현하여 이를 Endpoint(웹소켓 연결을 다루는, Servlet 역할에 해당하는 클래스입니다)로 등록해주면 됩니다.

그럼 spring-websocket이 제공하는 것은 무엇이냐?

바로 위 그림에서의 초록 부분인데 이를 포함한 전체 동작을 간단히 정리하면 아래와 같습니다.

  1. 웹소켓 연결을 위한 서블릿을 등록합니다(HttpRequestHandlerServlet)
    • 예: "/ws"
  2. 사용자로부터 웹소켓 연결 요청이 들어오면, 해당 서블릿이 필요한 핸들러를 호출해서 HTTP 연결을 WebSocket 연결로 업그레이드 하기 위한 핸드쉐이크와 업그레이드 과정을 거칩니다.
  3. 해당 과정에 WebSocketSession(HTTP 세션과 별개)을 만들고 Endpoint라는 메시지 핸들러를 만들어서 톰캣에 전달(doUpgrade)합니다.
  4. 사용자와의 HTTP 연결을 WebSocket 연결로 업그레이드 합니다. 이 과정을 거치고 나면 사용자와의 TCP 연결은 유지된 채, 서블릿 스레드를 반환하고, TCP 연결 정보가 톰캣 내 웹소켓 컨테이너로 이동합니다.
  5. 웹소켓 컨테이너는 서블릿 컨테이너와 달리, 멀티스레드가 아닌 NIO 기반 이벤트 루프, 즉, 여러 연결에 대해서 하나의 스레드가 새 메시지가 왔는지 계속 확인하는 방식으로 처리됩니다.
  6. 웹소켓 연결로 새 메시지가 오면 Endpoint로 등록된 StandardWebSocktHandlerAdapter(프록시입니다)가 WebSocketHandler에 메시지 처리를 위임합니다.
  7. WebSocketHandler에서 메시지를 핸들링하는 아주 복잡한 과정을 거치는데, 결국 메시지 브로커로 해당 메시지 처리가 넘어가고, 메시지 브로커가 라우팅을 거쳐 웹소켓 세션으로 메시지를 푸시합니다.
  8. 그렇게 푸시된 메시지가 클라이언트로 반환됩니다.

(혹여 잘못된 정보가 있으면 알려주시면 정말 감사하겠습니다🥲)

즉, 스프링 웹소켓은 웹소켓 처리를 위한 엔드포인트 등록부터, 연결 업그레이드, 웹소켓세션 관리 및 브로커와의 상호작용 부분을 추상화하여 제공합니다. SockJS와 STOMP에 대한 지원이 이 안에 녹아있습니다(업그레이드와 브로커, 메시지 처리 부분).

아래는 정리되지 않은, 제가 직접 따라가본 코드 구조에 대한 그림입니다. 오른쪽 위 클라이언트에서부터 왼쪽으로 따라가시면 됩니다.

마치며

스프링 Web MVC와 다르게 정확한 아키텍처와 동작 과정에 대한 자료가 많지 않아서 웹소켓 개발을 할 때 많은 어려움이 있었습니다. 같은 기술을 사용하시는 분들이 이해하는 데에 조금이라도 도움이 되었기를 바랍니다ㅎㅎ.

참고자료

profile
안녕하세요! 차근차근 성장하는 소프트웨어 엔지니어 박계현입니다😊

2개의 댓글

comment-user-thumbnail
2025년 6월 13일

좋은 자료 공유 감사합니다 나중에 채팅 구현할 일 있을 때 무조건 참고할 것 같아요 👍

1개의 답글