Please enable JavaScript.
Coggle requires JavaScript to display documents.
Spring WebSocket을 활용한 채팅 서버 - Coggle Diagram
Spring WebSocket을 활용한 채팅 서버
통신 프로토콜
WebSocket
Spring WebSocket
단순한 WebSocket API를 넘어, 엔터프라이즈 애플리케이션이 요구하는 메시징 아키텍처, 폴백 호환성, Spring 생태계 통합을 한번에 제공하기 위해 Spring Framework에 도입됨
특장점
비용 효율성
완전 무료 사용 가능
Spring WebSocket 모듈 자체를 완전 무료로 누구나 이용 가능
**단, Pivotal/VMware가 제공하는 상용 지원을 원할 경우, 그에 대한 연간 서포트 계약이 별도로 필요할 수 있음
개발 생산성 향상
추상화된 프로그래밍 모델
Spring MVC의
Controller
/
MessageMapping
애노테이션을 그대로 가져와, 메시지 핸들러를 선언형 방식으로 정의 가능
자동 설정 및 편의 API
EnableWebSocketMessageBroker
한 줄로 STOMP 엔드포인트, 메시지 브로커 설정이 활성화됨
SimpleMessagingTemplate을 통해 애플리케이션 레이어 어디서나 손쉽게 메시지 발행이 가능함
간단한 설정
"코드 몇 줄"로 설정 완료 가능:
registerStompEndpoint() / configureMessageBroker()
브라우저 / 프록시 호환성 보장
SockJS fallback 지원
"늘 연결된" UX 보장
일부 오래된 브라우저나 제한된 프록시 환경에서 WebSocket Upgrade가 실패할 수 있지만, Spring WebSocket은 SockJS를 통한 XHR 스트리밍/롱폴링으로 자동 폴백 지원
JSR-356 호환
표준 Java WebSocket API(JSR-356)를 지원하면서도,
애노테이션 기반의 Spring 스타일로 더 부드러운 통합을 지원
메시징 아키텍처와의 통합
spring-messaging 모듈
Spring Integration의 Message, MessageChannel, MessageHandler 추상화를 재사용해, REST 중심의 애플리케이션에 메시징 레이어를 자연스럽게 추가할 수 있음
STOMP 지원 / 유연한 브로커 선택
WebSocket 위에 STOMP를 얹어 발행/구독(Pub/Sub) 모델을 쉽게 구현할 수 있고, 브로커(SimpleBroker, RabbitMQ/ActiveMQ 릴레이) 선택도 자유로움
보안/트랜잭션 통합
Spring Security, Spring Transaction 등 기존 스프링 기능과 원활히 연동되어, 메시지 단위 인증/인가/트랜잭션 처리를 일관되게 사용 가능
등장 배경
HTML5 WebSocket 표준의 등장
IETF RFC 6455(2011)로 프로토콜이 확장되고, 브라우저들이 WebSocket을 지원하기 시작했지만, 직접 JSR-356(Java WebSocket API)를 쓰면, 낮은 수준의 연결 및 프레임 처리를 직접 구현해야 했음
엔터프라이즈 메시징 추상화 수요
Spring Integration에서 이미 쓰이던 Message / MessageChannel / MessageHandler 패러다임을 WebSocket 위로 확장해, STOMP 등 발행/구독 모델을
애노테이션 기반
(@MessageMapping
) + DI
방식으로 손쉽게 구현할 수 있게 함
Fallback 및 브라우저/프록시 호환성
초기 IE10 미지원, 일부 프록시가 Upgrade 요청을 차단하는 문제 등을 해결하기 위해, Spring WebSocket은 SockJS fallback(XHR 스트리밍/롱폴링)을 투명하게 지원하도록 설계됨
Spring 생태계와의 일관된 통합
Spring MVC, Spring Security, 트랜잭션 관리, 메시지 브로커 등을 기존 설정/보안 모델 그대로 재활용할 수 있게 함으로써, 실시간 통신 기능을
"몇 줄의 설정"
으로 추가할 수 있는 편의성 제공
단일 TCP 연결 위에서 클라이언트와 서버 간에 완전 이중(full-duplex) 통신 패널을 제공하는 프로토콜
등장 배경
HTTP polling, Long Polling 한계
주기적 요청 또는 이미 열림 요청이 종료될때까지 대기하는 방식은 불필요한 오버헤드와 지연을 초래
Comet 기술 복잡성
iframe, XHR 스트리밍 등으로 풀어냈지만, 구현이 까다롭고 브라우저별 차이도 큼
웹소켓은 이러한 문제를 해결하면서도 웹 보안 모델인
동일 출처 정책(Same-Origin Policy)
을 유지하며, 표준화된 양방향 통신을 가능하게 함
동작 방식
HTTP와 달리 최초 연결 시에만 HTTP 핸드셰이크(Upgrade)를 사용하고,
그 이후로는 메시지 프레임 교환만으로 양방향 통신을 지속(
소켓 커넥션을 유지
)
서버는 클라이언트의 요청 없이도 실시간으로 데이터를 푸시할 수 있음
클라이언트는 서버에 웹소켓을 연결한 상태로 유지하며, 언제든지 서버로부터 데이터를 받을 준비를 하고 있음
핸드셰이크 (Opening Handshake)
프레임 교환 (Message Framing)
연결 후에는 텍스트(opcode 0x1), 바이너리(opcode 0x2) 메시지를 포함해, Ping(0x9), Pong(0xA), Close(0x8) 프레임이 오간다
마스킹 (Masking)
클라이언트가 보내는 모든 프레임은 4바이트의 마스크 키를 사용해 페이로드를 마스킹해야하며, 이는 보안 및 캐시 회피 목적.
서버는 마스킹을 하지 않는다.
메시지는 하나 이상의 프레임으로 분할될 수 있으며,
FIN 비트로 완전 메시지의 시작과 끝을 표시
2 more items...
유지 / 종료
Ping / Pong
연결 상태 확인 또는 애플리케이션 레벨 하트비트 용도로 사용됨
1 more item...
클라이언트가
HTTP GET
요청에 Upgrade: websocket, Connection: Upgrade, Sec-WebSocket-Key 헤더 등을 포함해 전송
버전 협상
클라이언트는
Sec-WebSocket-Version
헤더로 지원하는 WebSocket 프로토콜 버전을 명시 -> 서버는 이 버전이 지원되지 않으면 426 응답코드와 함께 지원 버전을 명시해 연결을 거절할 수 있다
서브프로토콜
클라이언트는
Sec-WebSocket-Protocol
헤더로 하나 이상의 서브프로토콜(STOMP 등)을 제안할 수 있고, 서버는 그 중 하나를 선택해 응답에 명시함으로써 채택
확장
permessage-deflate와 같은 확장 기능은
Sec-WebSocket-Extensions
헤더를 통해 협상되며, 서버는 이를 수락하거나 무시할 수 있음
핸드셰이크 키
Sec-WebSocket-Key는 클라이언트가 생성한 임의의 Base64 인코딩된 키이며, 서버는 이 키에 고정 GUID를 덧붙여 SHA-1 해시 후 Base64 인코딩한 값을 Sec-WebSocket-Accept 헤더에 넣어 응답함으로써 연결의 유효성을 검증
서버는
상태코드 101
Switching Protocols와
Sec-WebSocket-Accept
헤더로 응답하며 프로토콜 전환을 확정
특징
풀 이중 통신(full-duplex)
단일 소켓으로 양방향 메시지 전송이 동시에 가능
낮은 오버헤드
첫 핸드셰이크 이후 HTTP 헤더 없이 최소한의 프레임 헤더(2~14바이트)만 사용
메시지 지향
TCP의 바이트 스트림 위에
메시지 단위
개념을 부여
브라우저 호환성
대부분 현대 브라우저에서 기본 지원
확장성
압축(premessage-deflate), 멀티플렉싱 등 확장 프레임워크 제공
보안 모델
동일 출처 정책 기반이지만, Origin 헤더 검증, 토큰 인증 등을 별도 구현 필요
장단점
성능
장점
: 실시간성, 저지연 ➡ 지속 연결과 낮은 오버
단점
: 다량의 동시 연결 시 서버 리소스(파일 디스크립터, 메모리) 부담 증가
개발 편의성
장점
: 표준화된 API(WebSocket 인터페이스), 다양한 클라이언트 라이브러리 제공
단점
: 상태 관리 (연결 상태, 재접속 로직) 직접 구현 필요
호환성
장점
: HTTP 포트(80/443) 사용, 방화벽/프록시 통과 용이 ➡ 별도의 포트 필요 없음
단점
: 일부 구형 프록시, 인터미디어리에서 Upgrade 미지원으로 연결 실패 가능
보안
장점
: TLS(wss://)를 통한 암호화, Origin 검증 구조로 XSS, CRSF 위험 완화 가능
단점
: CSWSH (Cross-Site WebSocket Hijacking) 등 신규 공격 벡터 존재 및 토큰 기반 인증/인가 보강 필요
TCP vs. UDP vs. WebSocket
UDP
특징
비연결성(커넥션 설정/해제 없음)
최소한의 헤더(8바이트)로 빠른 전송 지원
순서 보장/재전송 없음
장점
지연 최소화
멀티캐스트/브로드캐스트 지원
단점
패킷 손실, 중복, 순서 뒤바뀜 가능
신뢰성 확보는 애플리케이션 레벨에서 처리해야 함
TCP
특징
연결 지향적
신뢰성(순서 보장, 재전송)
흐름 제어, 혼잡 제어 기능 제공
장점
데이터 무결성 보장
간단한 구현
단점
헤더/제어 오버헤드
실시간성이 중요한 환경에서는 지연 발생 가능성
WebSocket
특징
HTTP 핸드셰이크(Upgrade 헤더) 후,
단일 TCP 연결 위에서 양방향 메시지 프레임을 주고 받음
장점
실시간성이 뛰어남
HTTP 포트(80/443)를 사용해 방화벽 통과가 용이
단점
TCP 기반이므로 UDP만큼 지연이 낮지는 않지만, 대부분 실시간 웹 채팅/알림 용도로 충분
STOMP 프로토콜
(Simple Text Oriented Messaging Protocol)
텍스트 기반의 메시징 프로토콜로, 클라이언트와 메시지 브로커(또는 서버) 간에 메시지를 주고받기 위한 단순하면서도 범용적인 프레임 기반 형식을 정의
HTTP와 유사하게 CONNECT, SEND, SUBSCRIBE, UNSUBSCRIBE, ACK, NACK, DISCONNECT 등 명령어 기반으로 동작하며, TCP나 WebSocket위에 얹어 사용할 수 있다
채팅 메시지 프로토콜로서의 STOMP
추상화된 발행/구독 모델 (Publish/Subscribe)
STOMP의 SUBSCRIBE / SEND 명령어를 활용하면 목적지(destination) 별로 메시지를 라우팅할 수 있어, 채팅방(room) 단위 구독이 자연스러움
언어/플랫폼 독립성
Java, JavaScript, Python 등 다양한 클라이언트 라이브러리가 존재해 멀티 플랫폼 지원이 용이함
단순한 텍스트 프레임
디버깅과 로깅이 쉽고, 바이너리 페이로드도 지원
채팅 서버 선택지 비교
Spring WebSocket
추상화 레벨
: 높은 수준의 API (STOMP 통합)
성능/확장성
: 적절 (내장 Tomcat / Jetty / Netty)
개발 생산성
: 대규모 프레임워크의 원활한 통합
커뮤니티/생태계
: 방대한 Spring 생태계
STOMP + Spring WebSocket
빠른 개발 생산성과 Spring 생태계 통합성이 뛰어나며,
중대형 채팅 서비스에서 충분한 성능 제공
핸드셰이크 성립 후 WebSocket 프레임(텍스트/바이너리)을 직접 주고받는 과정에서 STOMP 프레임이 이 위에 subprotocol로 얹혀 전송된다
Netty
추상화 레벨
: 낮은 수준의 NIO 프레임워크
성능/확장성
: 매우 높음 (비동기, 이벤트 드리븐)
개발 생산성
: 러닝 커브 있음, 세밀한 튜닝 필요
커뮤니티/생태계
: 네트워킹 특화 커뮤니티
대규모 동시 접속 처리나 특별한 맞춤형 로직이 필요할 때 고려할 만하지만,
개발/운영 복잡도가 더 높음
자체 WebSocket 서버
Node,js의 ws 라이브러리는 매우 가볍고 설정이 단순하지만, 멀티 프로세스 수평 확장이나 메시지 브로커 연동(예: Redis Pub/Sub) 등을
추가로 구현
해야 함
서버 간 클러스터링, 인증/인가, 부하 분산 로직을
직접 설계 및 구축
해야하므로,
운영 복잡도가 상승
함