시작하며
현재 진행중인 프로젝트에서 웹소켓을 활용한 기능 구현을 검토중입니다.
웹소켓을 적용하기 전에 알아봐야할 것들, 고민할 것들을 아래 질문 형태로 기록해둡니다.
웹소켓이란?
웹소켓이 해결하려는 문제는 Real-Time Collaboration on Web (웹기반 실시간 커뮤니케이션)이다.
대표적으로 Trello, Google Docs 와 같은 서비스들이 있다.
웹소켓의 주요 특징
- Statefulness
- Low Latency
- 2 Way Push (Bi-Directional)
- 브라우저/서버간 통신 Standard(규약)이 필요하다.
- 1개의 TCP 커넥션을 사용한다. (1 WebSocket per 1 TCP Socket Connection)
- Message-based
웹소켓의 Phases
- Opening Handshake (연결을 위한 핸드쉐이크)
- Exchange Data (데이터 교환)
- Closing Handshkae (종료를 위한 핸드쉐이크)
Opening Handshake (연결을 위한 핸드쉐이크)
- Request 요청
- HTTP/S (v.1.1 or up) 의 GET 메서드와 Upgrade 헤더로 시작한다.
- 핸드쉐이크 과정에서 필요한 협의 내용으로 protocol version, subprotocol, extensions 이 있다.
- Response 응답
- Status 101 (Switching Protocols)로 성립
웹소켓 Frame Types
웹소켓의 message는 1개 이상의 frame들로 구성되어 있다. 웹소켓 메시지 Frame의 4-bit Opcode에 표기되는 타입은 아래와 같이 7가지가 존재한다.
- Data Frame
- Text
- Binary
- Control Frame
- Ping (서버에서 전송하는 메시지 / 사용자가 Pong으로 응답하지 않으면 커넥션을 종료한다)
- Pong (Ping에 대한 응답 / 서버로 전송 Heartbeat이라고도 한다)
- Close
웹소켓 Best Practices
- 상세하게 협의하기 (version, subprotocol, extensions... 등)
- 일찍부터 확장을 준비하기 (rsv bits, payload size, extensions... etc)
- 비-엔드포인트를 염두하기 (캐싱)
웹소켓 고려사항
- 정말로 정말로 양방향 커뮤니케이션이 필요한가?
- 해결하려는 문제에 TCP, UDP, 또는 RUDP를 적용한 경우와 비교해보기
- 웹소켓의 Statefulness를 어떻게 관리할 것인가?
웹소켓 Use Cases
1. 채팅 / 메신저
- Slack, Discord
- request 가 아닌 서로에게 푸시방식으로 메시지를 전달
2. 라이브피드 / 협업툴
- Trello, Google Docs
- 연결 후 지속적으로 컨텐츠 전달
3. 멀티플레이어 게이밍 (**아래에서 추가로 다룰예정)
- 여러 클라이언트가 웹소켓으로 연결
- 서버가 웹소켓 커넥션을 유지해야한다.
- Scale-Out 하기 상대적으로 손이 많이 간다.
4. 모니터링 (업로드 상태, BI 지표)
- 비디오 렌더링
- 업로드
웹소켓의 장점
- (Full-Duplex) 완전한 양방향 통신, 서버와 클라이언트 모두 주도적인 메시지 전송이 가능하다. 즉 polling이 불필요하다.(HTTP 를 활용하는 polling새로운 메시지 있어요? 새로운 메시지 있어요? 새로운 메시지 있어요? 새로운 메시지 있어요? 새로운 메시지 있어요? 새로운 메시지 있어요? 새로운 메시지 있어요? 이런거 안해도 된다.)
- 헤더를 활용한 HTTP 호환성. 프록시와 방화벽 친화적임.
- 메시지의 크기가 가볍다. 매번 헤더와 함께 데이터를 전송하지 않음. long-polling의 경우 매번 완전한(full) HTTP 요청을 전송하기 때문에 상대적으로 데이터의 크기가 클 수 밖에 없다.
웹소켓의 단점
- 프록시-ing 하기가 상대적으로 까다롭다. (예를들어 웹소켓을 지원하지 않는 경우도 있음)
- 웹소켓 지원하지 않은 프록시가 있다.
웹소켓의 SubProtocol Negotiation
-
WebSocket은 각 메시지의 포맷을 추측(assumption)하지 않는다. 1 bit로 표시된 text 형식, 또는 binary 형식 여부만을 확인해서 decode한다.
-
추가로 Header를 활용해서 추가적인 메타데이터를 전달하는 HTTP의 그런 메커니즘이 WebSocket에는 없다. 그래서 subprotocol 을 사용하게되는데, 이 부분은 client와 server 가 협의를 해야한다. 몇가지 예를 살펴보면...
-
예를들어 클라이언트와 서버가 미리 메시지 포맷을 정의할 수 있다. JSON, 커스텀 바이너리 등....
-
text 데이터를 HTTP Header 와 같이 정의하고 이후의 데이터를 binary 형식으로 전송할 수 도 있다.
-
Masking WebSocket Payload
-
클라이언트에서 생성된 모든 WebSocket 메시지 프레임은 마스킹처리되서 서버로 전송된다.
-
Masking은 프록시 레이어에서 데이터가 의도치않게 Cacheable한 HTTP Request로 읽히는 것을 방지하기 위해 사용된다.
웹소켓 적용 사례는?
적용사례 예시 1.
웹소켓의 가장 근본적인 적용사례는 채팅이다. 채팅이 커넥션이 맺어져있는 동안 정말 빠르게 여러 데이터를 주고받는 경우를 의미한다는 전제하에. 사용자와 사용자 간에 양방향 통신이 필요하고, 그 시간은 빠를 수록 좋기때문에!
적용사례 예시 2.
배달서비스에서 라이더의 위치 정보 업데이트기능 + 메시지 Push 기능을 웹소켓을 통해 구현한다.
위치정보를 위해 수시로 http 요청을 보내는 것은 무리가 있다는 판단하에 웹소켓을 사용한다.
Scale-Out을 위해 웹소켓 세션이 어느 서버에 있는지에 대한 라우팅 정보를 Redis 에서 관리하도록 한다.
우버 Uber 에서는 카프카를 통해 처리했다고 한다.
웹소켓이 정말 게임 분야에서도 사용이될까?
내가 수집한 웹소켓의 유즈케이스들 중 가장 눈에 띄었던 부분은 Multiplayer Real-Time
- 게임 분야에서는 성능 최적화의 이유로 TCP 소켓을 직접 사용하는 경우가 대부분이다.
- 사실 게임 분야에서 웹소켓이 필요한 경우는 웹, 또는 웹소켓 기반 게임을 만들 때이다.
- 중요한 것은 TCP 소켓은 TCP 레이어에서 동작하고 웹소켓은 HTTP 레이어에서 사용된다는 점.
- 웹소켓은 추상화가 더 되어있다. 게임 분야에서 TCP, UDP, RUDP 가 있다.
WebSocket과 TCP 소켓은 왜 유의미한 성능차이가 발생할까? 성능 차이는 얼마나 날까?
위에서 언급한 것처럼 웹소켓 보다 TCP 소켓의 성능(속도)가 뛰어나다고 한다. 왜 성능 차이가 발생할까? 얼마나 성능 차이가 나길래? 네트워크 모델/레이어 관점에서 생각해보자.
OSI 네트워크 레이어 기준 TCP Socket은 Layer 4 (Transport Layer of TCP/IP) 에 포함되고 WebSocet은 Layer 7 (Applicaiton Layer ofTCP/IP) 에 포함된다. 레이어가 올라가는(ex. layer 1에서 layer 2로 이동하는)만큼 Envelop 개념이 더 적용되며 추상화가 더 이루어진다. 같은 데이터를 어디서는 4겹으로 감싸고 다른 한곳에서는 7겹으로 감싼다고 생각해보면 쉽다.
WebSocket 구현하기
(진행중)
출처
- www.youtube.com/watch?v=9FqjRN4VYUU
- https://www.youtube.com/watch?v=2Nt-ZrNP22A
- https://hpbn.co/websocket/
- https://keyholesoftware.com/2015/03/16/netty-a-different-kind-of-websocket-server/
- https://stackoverflow.com/questions/8156254/tcp-vs-udp-what-is-a-tcp-connection
- 출처 for 웹소켓이 게임 분야에서도 사용이될까? (F-Lab의 엘키님 / HwanJo님 / 코딩하는-Squid님)
- www.vinsguru.com/spring-webflux-websocket/
'개발상식' 카테고리의 다른 글
버그 발생 비용의 세부 요소 분석 (1) | 2023.11.24 |
---|---|
더 빨리 움직이면서 느려지는 우리를 위해서, 클린코더의 교훈 (0) | 2023.11.11 |
성능과 메모리 효율 관점에서 JDK 의 ArrayDeque, Stack, LinkedList 비교 (0) | 2023.07.15 |
“테스트의 사실과 오해” 컨퍼런스 발표 내용 (0) | 2023.07.04 |
백엔드 개발 기초 배경 부분 모음집 (2) | 2022.06.04 |