이번 프로젝트 때 스프링 부트로 1 : 1 채팅을 구현해야 합니다. 그래서 여러 가지 내용을 열심히 공부해 봤습니다.
프로젝트 채팅 1 : 1 조건
- 고민 상담 게시판에서 채팅방이 시작됨
- 채팅 매칭을 누르면 채팅방이 생성
- 대화를 한 내용은 DB에 저장
- 세션 값을 가지고 있어야 한다.
WebSocket을 선택한 이유
WebSocket은 양방향 실시간 통신을 제공하는 프로토콜 및 API(응용 프로그래밍 인터페이스)입니다. 일반적으로 웹 브라우저와 웹 서버 간의 실시간 통신을 위해 사용됩니다. WebSocket은 기존의 HTTP 프로토콜을 확장하여 지속적인 연결을 제공하고, 클라이언트와 서버 간에 데이터를 양방향으로 주고받을 수 있게 합니다.
WebSocket을 사용하기 전
일반적으로 웹은 클라이언트에서 서버로 HTTP 요청을 보내고, 서버는 해당 요청에 대한 응답을 반환하는 요청-응답 기반의 통신 방식을 사용합니다. 즉, HTTP로도 실시간성을 보장해 줄 수 있습니다. 그 방법들이 폴링(Polling)이나 롱 폴링(Long Polling), 스트리밍 같은 추가적인 메커니즘입니다.
- 폴링(Polling)
폴링은 클라이언트가 일정한 간격으로 서버에 주기적으로 요청을 보내는 방식입니다. 클라이언트는 주기적으로 서버에 데이터를 요청하고, 서버는 요청에 대한 응답으로 데이터를 반환합니다. 클라이언트는 주기적인 요청을 보내야 하기 때문에 상황에 따라 불필요한 네트워크 트래픽과 지연이 발생할 수 있습니다.
- 롱 폴링(Long Polling)
롱 폴링은 폴링의 개선된 형태로서, 클라이언트가 서버에 요청을 보내고 서버는 즉시 응답하지 않고 대기합니다. 서버는 새로운 데이터 또는 이벤트가 발생할 때까지 응답을 지연시키며, 클라이언트는 지연된 응답을 받으면 다시 요청을 보냅니다. 이 방식은 폴링의 불필요한 요청을 줄이고, 서버에서 즉시 데이터를 전송할 수 있는 상황에 최적화된 방식입니다.
- 스트리밍(Streaming)
스트리밍은 연결을 유지한 상태에서 실시간으로 데이터를 전송하는 방식입니다. 클라이언트가 서버에 연결을 설정하면, 서버는 연결을 유지하고 새로운 데이터가 생성되는 대로 클라이언트로 데이터를 전송합니다. 이를 통해 실시간으로 데이터를 수신하고 처리할 수 있습니다. 스트리밍은 연결을 유지해야 하므로, 다른 방식에 비해 더 많은 리소스를 사용할 수 있습니다.
이렇게 3가지 방법으로 HTTP도 실시간성을 보장할 수 있습니다. 하지만 단점이 확실하게 보입니다. HTTP는 비 연결성이고 매번 연결을 맺고 끊는 과정이 필요합니다. 요청과 응답의 구조이기 때문입니다.
이에 비해 웹 소켓은 연결을 지향하고 한번 연결을 맺은 뒤 유지하려고 합니다. 그리고 양방향 통신입니다.
웹 소켓의 장점
- 학교 컴퓨터 네트워크 시간에 배운 것을 생각해 봅시다. HTTP가 요청을 하고 응답을 한 뒤 끊으려면 3,4 handshake를 해야 합니다. 하지만 웹 소켓은 그런 과정이 필요가 없습니다.
- HTTP는 요청과 응답이 한 쌍을 이루는 구조입니다. 요청을 하면 무조건 응답을 줘야 합니다. 하지만 웹 소켓은 상대가 보낸 응답을 듣기만 하면 되는 구조입니다.
- HTTP는 정보를 보내는 양도 많습니다. 컴네시 간에 배운 HTTP 구조를 생각하시면 될 것 같습니다. 하지만 웹 소켓은 한 번 연결이 된 이후에 JSON 타입의 정보만 보내주면 됩니다.
웹 소켓을 사용 할 수 있는 곳
https://caniuse.com/?search=websocket
이건 when i use라는 사이트입니다. 빈칸 안에 내용을 어디에 사용할 수 있는지 알려줍니다. 대중적인 HTTP/2와 거의 비슷하게 웹 소켓도 많이 사용할 수 있다는 것을 볼 수 있습니다. 유저들이 즐겨 쓰는 Chrome에서도 옛날 모델이 아니면 잘 지원해 줍니다.
STOMP
STOMP (Simple Text Oriented Messaging Protocol)는 간단한 텍스트 기반 메시징 프로토콜로, 클라이언트와 서버 간의 상호작용을 위한 표준화된 메시징 프로토콜입니다. STOMP는 대부분의 메시징 중개인과 통합할 수 있는 널리 사용되는 프로토콜입니다.
WebSocket은 실시간 양방향 통신을 지원하는 프로토콜이며, 웹 브라우저와 웹 서버 간의 연결을 단 한 번 설정하고 그 상태를 유지합니다. 그러나 WebSocket 자체는 메시징 프로토콜이 아닙니다. 따라서 WebSocket을 통해 실시간 메시징을 구현하기 위해서는 별도의 메시징 프로토콜이 필요합니다. 이때 STOMP가 사용될 수 있습니다.
STOMP의 특징
- 단순성 : STOMP는 간단하고 이해하기 쉬운 텍스트 기반 프로토콜입니다. 메시지 구조가 단순하며, 명령어와 헤더를 사용하여 메시지를 정의하고 전달합니다.
- 프로토콜 중립성 : STOMP는 프로토콜 중립적인 특성을 갖고 있어서 다양한 메시징 시스템과 통합될 수 있습니다. RabbitMQ, ActiveMQ, Apache Kafka 등과 같은 메시징 중개인들은 STOMP를 지원하는 경우가 많습니다.
- 언어 독립성 : STOMP는 다양한 프로그래밍 언어와 플랫폼에서 사용될 수 있습니다. Java, Python, JavaScript, Ruby,. NET 등 다양한 언어에서 STOMP 클라이언트를 사용하여 메시징 기능을 구현할 수 있습니다.
- 메시지 전송 및 구독 : STOMP는 메시지 발행(Publish)과 구독(Subscribe)을 지원하여 실시간 메시지 통신을 구현할 수 있습니다. 클라이언트는 특정 주제(topic)에 대해 구독하고, 해당 주제로 발행된 메시지를 수신할 수 있습니다.
- 헤더와 프로퍼티 : STOMP는 헤더와 프로퍼티를 사용하여 메시지의 메타데이터를 전달할 수 있습니다. 이를 통해 메시지의 속성과 추가 정보를 전송할 수 있습니다.
STOMP를 사용한 WebSocket의 실시간 메시징 과정
- 클라이언트는 WebSocket을 통해 서버에 연결을 설정합니다.
- 연결이 설정된 후, 클라이언트는 STOMP 클라이언트 라이브러리를 사용하여 STOMP 프로토콜을 통해 메시징 기능을 구현합니다. 이때 STOMP 클라이언트는 WebSocket을 통해 서버와 통신하며, STOMP 프로토콜의 명령어와 메시지 형식을 사용하여 메시지를 발행하고 구독하거나 기타 작업을 수행합니다.
- 서버는 STOMP 프로토콜을 구현한 STOMP 핸들러를 사용하여 클라이언트의 요청을 처리합니다. 서버는 클라이언트로부터 받은 STOMP 메시지를 해석하고, 필요한 작업을 수행한 후 응답을 반환합니다.
STOMP의 Publish와 Subscribe에 대해서
stomp 프로트콜은 pub/sub 방식을 사용하여 Message Broker를 통해 작업을 수행하거나 메시지를 보냅니다.
- pub/sub 방식
- Stomp를 공부하면서 pub/sub 방식에 대해 처음 알았습니다.
- 메시지를 공급하는 주체와 소비하는 주체를 분리하여 제공하는 메시징 방법입니다.
- 제가 이해한 방식으로 쉽게 설명하자면 유튜브 채널(topic)이 있습니다. 유튜브 채널의 주인은(publisher) 채널에 영상을 올립니다. 그러면 우리 같은 구독자(subscriber)는 그 영상을 보게 되는 것입니다.
- 채팅으로 설명하자면 채팅을 적는 사람은 publisher 입니다. 이 publisher이 채팅방 (topic)에 채팅을 보냅니다. 그러면 subscriber 채팅을 같이하는 사람이 채팅을 보게 되는 것입니다.
- Message Broker
- 발신자의 메시지를 받아와서 수신자들에게 메시지를 전달하는 것입니다.
Websocket과 STOMP만을 사용했을 때 문제점
지금까지 Websocket과 STOMP 프로트콜로 실시간 채팅을 구현하기로 결정했습니다. 이제 단점이 없어 보이지만 단점이 남아 있었습니다.
- Websocket과 STOMP로 채팅서버를 구현하고 성공적으로 메시지를 보낸 뒤 서버를 다시 down 했다가 키면 Message Broker의 내용들이 모두 날아갑니다.
- 왜냐하면 스프링에서는 Simple Message Broker를 사용해 채팅 서버를 구현합니다. 하지만 이것은 스프링 부트 서버의 내부 메모리에서 동작하게 됩니다.
- 또, 현재 다수의 서버일 경우 서버간 채팅방을 공유할 수 없습니다. 즉, 다른 서버 간에 있는 사용자와의 채팅이 불가능 해집니다. 예를 들어, 우리의 프로젝트가 성공해서 유저가 많아져 로드 밸런스를 해야 한다고 가정해 봅시다. 8080으로 연 서버와 8090으로 서버를 2개 열었습니다. 지금 상황은 이 2개의 서버가 서로 채팅을 주고받을 수 없습니다.
Redis를 사용하여 pub/sub 구현하기
Redis는 STOMP 프로토콜을 지원하지 않지만, Redis가 제공하는 Pub/Sub 기능을 통해 메시지 중개인으로 사용할 수 있습니다.
Redis 말고 STOMP 프로토콜을 지원하는 RabbitMQ와 같은 전용 메시지 브로커를 사용하면 더 고도화된 기능(메시지 전달 보장, SSL 지원)을 사용할 수 있습니다. 이건 2차 과제로 생각하고 있습니다.
- Redis를 사용하면 구독 대상인 채팅방(topic)을 DB에도 Redis에도 저장해 놓는 것입니다.
- 다른 서버에서 입장하면 Redis에서 채팅방을 찾아 접속 시켜 줍니다.
- 이렇게 하면 어떤 서버든 그 채팅방을 구독하고 있으면 메시지를 보낼 수 있습니다.
지금 까지 WebSocket과 STOMP와 Redis를 왜 선택했는지에 대한 이유를 설명했습니다!!
이제 남은 과제는 많은 양의 메시지를 어떻게 처리할 것이며 (지금은 DB에 저장해야 할 것 같음) 채팅 서버 안에서의 보안 문제에 대해 생각하고 있습니다.
채팅 성공 영상
'토이프로젝트 > 나만의 프로젝트' 카테고리의 다른 글
토큰 기반 인증으로 로그인 업그레이드 하기(JWT) (0) | 2023.06.28 |
---|---|
스프링 시큐리티로 회원가입, 로그인 구현하기 (0) | 2023.06.27 |
테스트 코드 공부 (0) | 2023.06.21 |
Docker로 CI/CD 구축하기 (0) | 2023.06.20 |
데이터베이스 정규화 하기 (2) | 2023.04.29 |