티스토리 뷰
들어가는 말
- WebSocket 을 좀 봐두어야 할 시점이 되어 정리
WebSocket 이란
- 하나의 TCP 커넥션으로 full duplex 통신을 제공하는 프로토콜
- HTTP 와 호환되지만 동일하지는 않다고 함
- HTTP 포트 80, 443 위에서 동작하도록 설계
- 초기 연결 이후 Upgrade Header 를 사용 (https://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header)
- HTTP 포트 80, 443 위에서 동작하도록 설계
- 이후 WebSocket / WS 용어 혼용
WebSocket 의 필요성
- 서버에서 발생한 이벤트를 클라이언트에 전달하기 위하여 사용
- WebSocket 이전까지
- 클라에서 클라 본인이 갱신 된 변경사항이 있는지 주기적으로 요청하여 확인
- polling 방식
- 꼭 필요하지 않은 상황에서도 통신이 발생 (클라 입장에서는 주기적으로 호출할 뿐이므로)
- 구현 난이도는 쉽다고 생각
- 클라나 서버에서 구현 자체는 쉬울수도 있음
- 리소스 관리 (커넥션, 서버 자원) 측면에서는 골치 아파질수도
- 클라가 길게 접속하도록 허용하며 변경 사항이 있을 경우 그 시점에서 응답
- long polling 방식
- (이 방법을 고려해본적이 없으므로 정확한 장단점을 이해하기 어려움)
- Transfer-Encoding : chunked 로 지속적으로 커넥션을 유지
- 클라쪽에서는 커넥션이 끊어지면 다시 요청
- 폴링 방식을 개선하기 위해 나온것으로 기억하고 있으며, 특히 커넥션을 새로 맺는 과정 자체를 줄이기 위한것으로 보임
- 클라이언트마다 커넥션이 살아 있는것은 동일
- 추가로 응답을 기다리고 있는 여러 클라이언트에 동시에 응답을 처리하는 과정에서 부하가 생긴다는 말도 있음
- WebSocket 에서는
- 최초 HTTP 요청(정확히는 WebSocket 을 사용하기 위한 기반 요청)을 통해 WebSocket 커넥션 생성
- 수립된 WebSocket 연결을 통해 full duplex 로 서버와 클라가 통신
- 클라이언트마다 커넥션이 살아 있는 것은 동일
- 역시나 이 방법도 L4 나 Haproxy 같은 reverse proxy 에서는 live connection 이 많아지므로 부하가 많아지지 않을까
- SSE(Sever Sent Event) 에서는
- WebSocket 키워드를 들어본 시점이 SSE를 들어본 시점보다 빠르므로 후기에 나온 기술이지 않을까 추정
- 아님
- 서로 목적이 다른 장단점이 있는 기술
- 본 문서의 목적에 벗어나므로 SSE를 파보는건 다음으로
- 차이점
- WebSocket 은 양방향 통신을 지원하지만 SSE는 단방향 (Server -> Client) 을 지원
- 클라에서 동작이 필요하지 않다면 SSE가 더 적합할 수도 있음
- WebSocket 은 브라우저에서 지원하지 않을때 fallback 프로토콜을 별도로 구현해야하지만 SSE는 클라이언트 기술이므로 서버에서 고려 사항이 적다고 함
- SSE는 maximum open connections limit 이 존재한다고 함 (그럼 WS는?)
- WebSocket 은 양방향 통신을 지원하지만 SSE는 단방향 (Server -> Client) 을 지원
- WebSocket 키워드를 들어본 시점이 SSE를 들어본 시점보다 빠르므로 후기에 나온 기술이지 않을까 추정
- 클라에서 클라 본인이 갱신 된 변경사항이 있는지 주기적으로 요청하여 확인
- HTTP 3.0 기반의 WebTransport 가 있지만 글 작성 시점 (2021.08.) 에서 많이 활성화 된 것으로 보이지는 않음 (못찾은걸수도)
- 자세한 사항은 다음 글 및 아티클 참조
번외 - STOMP
- https://stomp.github.io/
- WS 관련 구글링을 하던 중 STOMP 라는 키워드가 종종 등장
- 스택오버플로에서 WS랑 STOMP가 무슨 차이냐? 라는 질문에 대한 답은 TCP랑 HTTP가 뭐가 다르냐? 라는 질문과 동일하다고 함
- https://stackoverflow.com/questions/40988030/what-is-the-difference-between-websocket-and-stomp-protocols
- STOMP는 WS 위에서 동작하는 텍스트 기반의 메시징 프로토콜
- 꼭 WS 위에서 동작할 필요는 없는것으로 보이며 MQ 관련된 내용도 다수 발견
- 이후 필요할 경우 재정리
중간정리
- HTTP 프로토콜 기술 발전에 따라 서버와 클라간에 실시간 통신을 위하여 여러가지 기술들이 발전해 왔음
- WS는 실시간성 양방향 바이너리 통신이 지원
- SSE와 WS 는 선행, 후행기술이 아니며 성격이 다른 기술
- 다음 진행 사항
- spring 관점에서 websocket 파악
- spring websocket 과 stomp
백각이 불여일행
- https://spring.io/guides/gs/messaging-stomp-websocket/
- 문서와 설명이 잘 되어있으므로 해당 가이드를 따라가 봄
- 이후 특이사항 기록
- 최초 spring initializr 로는 WebSocket 만 추가
- 검증에 클라이언트 부분을 필요로 하는것으로 보이며 의존성 필요
- @EnableWebSocket, @EnableWebSocketMessageBroker 무슨 차이일지
- 딱히 특이사항은 없는듯 (차라리 리눅스에서 했으면 했지 윈도우에서는 개발하지 말자...)
- connection 버튼 동작
- 메시지 전송
- 동시에 접속한 다른 커넥션에서도 잘 수신되는것을 확인
- 일단 대충은 알겠는데 대충만 알겠음 -> 스프링 레퍼런스 문서 확인 필요
spring guide
- servlet 기반 문서로 확인
- reactive stack 기반 문서도 있으므로 이후 필요할 경우 참조
- 번지수를 잘못 찾음
- 가이드에서 제공하는 방법은 @EnableWebSocket 기반으로 보이며 직전에 해본 @EnableWebSocketBroker 와는 차이가 있음
- @EnableWebSocketBroker은 STOMP 을 상정한 더 구체화된 사항으로 보임
- https://stackoverflow.com/questions/51474358/what-is-the-difference-between-enablewebsocket-and-enablewebsocketmessagebroke
- http://rstoyanchev.github.io/s2gx2013-websocket-browser-apps-with-spring/
- 가이드에서 제공하는 방법은 @EnableWebSocket 기반으로 보이며 직전에 해본 @EnableWebSocketBroker 와는 차이가 있음
HTTP와 WS의 차이
- WS가 HTTP와 호환되고 HTTP 연결을 통해서 시작하지만, 두 프로토콜은 아키텍쳐와 목적이 다름
- HTTP와 REST는 요청과 응답 동작을 근간으로 리소스들에 매핑된 여러개 URL, HTTP Method, HTTP Header 들에 기반으로 동작
- WS 의 경우는 하나의 URL 을 통해 커넥션을 수립하며, 이후 TCP 연결을 기반으로 메시지들이 '비동기','이벤트드리븐','메시징기반' 으로 처리
- WS 자체는 로우레벨 프로토콜이며 HTTP 와 다르게 메시지 자체에 의미가 부여되어 있지 않음 (REST 랑 비교해서도)
- 별도의 상위(구체화)된 프로토콜을 사용할 수도 있지만 여기서는 STOMP를 사용
WebSocketHandler
- WebSocketHandler 를 implement 하거나 이미 구현된 TextWebSocketHandler, BinaryWebSocketHandler를 extends 하는 방법 존재
- WebSocketConfigurer implements 해서 @EnableWebSocket 걸고 registerWebSocketHandlers를 통해 path 에 맞는 handler bean 등록
- WebSocketHandler에서 사용하는 WebSocket session (JSR-356) 은 concurrent 한 전송을 허용하지 않으며 동기화에 대한 책임은 어플리케이션에 있다고 함
- 가이드에서 제안하는 Decorator 쓰는 방법이 있긴 한데 (https://docs.spring.io/spring-framework/docs/5.3.9/javadoc-api/org/springframework/web/socket/handler/ConcurrentWebSocketSessionDecorator.html)
WebSocket Handshake
- registerWebSocketHandlers 에서 ws handshake 과정을 커스터마이징 할 수 있음 (before, after)
- DefaultHandshakeHandler를 상속하는 방법도 가능
- sub protocol 을 결정한다던가 인증에 사용할 수 있음
- 그외에 WebSocketHandlerDecorator를 써서 WebSocketHandler의 추가적인 동작을 덧붙일수도 (로깅, 익셉션 핸들링)
Deployment
- Spring WebSocket API는 Spring MVC와 쉽게 통합 가능
- DispatcherServlet 에서 HTTP WebSocket handshake이나 그외 HTTP 요청 처리
- The Java WebSocket API (JSR-356)은 두가지 배포(등록?) 메커니즘이 있음
- TODO 이 부분은 정확하게 이해하지 못했으므로 기록후 재확인
- 1) 스타트업 시점에서 서클릿3의 서블릿 컨테이너 클래스 패스 스캔을 통한 등록
- 2) 서블릿 컨테이너 초기화 과정에서 registration API를 사용하는 방법
- 하지만 두가지 방법 모두 DispatcherServlet 과 같은 WebSocket handshake 와 HTTP 요청을 청리하는 "front contrller" 역할을 하지는 못함
- (앞서 DispatcherServlet 이 엄밀히는 두가지 모두 지원하지만 동시에는 안된다는 말인가? 아니면 명시적으로 서버를 분리하라는 소리인가?)
- (그것도 아니라면 Spring WebSocket 과 Java WebSocket API JSR-356은 명백히 다른것을 지칭하는것이려나)
- 여기도 구현체가 다른듯 과거 문서 확인 시 명시
- Spring Framework 4 includes a new spring-websocket module with comprehensive WebSocket support. It is compatible with the Java WebSocket API standard (JSR-356) and also provides additional value-add as explained in the rest of the introduction.
- 그 다음 고려사항으로 Servlet containers with JSR-356 support 에서는 ServletContainerInitializer (SCI) 이 어플리케이션 스타트업을 느리게 만들 수 있음
- TODO 선택적으로 를 써서 web fragments (and SCI scanning)을 활성화하라고 함
Server Configuration
- ServletServerContainerFactoryBean을 빈으로 등록해서 런타임 프로퍼티 등록 가능
- WAS에 따라 다름
- 클라이언트쪽 WebSocket 설정을 위해서는 ContainerProvider.getWebSocketContainer()를 사용하라고 함
Allowed Origins
- 기본 방침은 to accept only same-origin requests
- Cross Origin 을 위해서라면 별도 처리 필요
- 정책상 3가지 방법 존재
- Allow only same-origin requests (default)
- Allow a specified list of origins
- Allow all origins
- 어떤 정책이냐에 따라서 IE 버전별로 지원이 되는 부분이 있고 지원되지 않는 부분이 있음
- SockJS fallback 에 따라서 다른듯
- 핸들러 등록 시점에서 .setAllowedOrigins("https://mydomain.com") 방법으로 가능
나가는말
- 스프링 레퍼런스 문서에서 SockJS Fallback, STOMP 항목은 일단 봐보고 필요하다면 정리
- STOMP은 정리가 필요할것 같음
레퍼런스
https://www.itfind.or.kr/publication/regular/weeklytrend/weekly/view.do?boardParam1=8034&boardParam2=8034
https://til-perfectacle.netlify.app/2018/11/18/http2-websocket-sse/
https://hamait.tistory.com/792
https://stackoverflow.com/questions/40988030/what-is-the-difference-between-websocket-and-stomp-protocols
https://velog.io/@gillog/Protocol-STOMP
https://spring.io/guides/gs/messaging-stomp-websocket
https://developer.mozilla.org/ko/docs/Web/API/WebSocket
https://www.baeldung.com/websockets-spring
https://velog.io/@koseungbin/WebSocket
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#websocket
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- COMMIT
- 기술사이트
- 기술센싱
- 사기꾼증후군
- 개발자
- meta character
- jhipster
- 만들면서 배우는 클린 아키텍처
- AWS
- percolate
- completablefuture
- WebSocket
- Kafka
- 말의품격
- 클린 아키텍처
- flush
- elasticsearch
- kafka 2.8.0
- Java
- 전설로떠나는월가의영웅
- opensearch
- 기술블로그
- fsync
- pecs
- Spring
- 에픽테토스
- Async
- Dangling
- Generic
- PatternSyntaxException
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함