본문 바로가기
Spring/WebSocket

[Spring WebSocket] STOMP를 활용한 채팅 서비스 토이 프로젝트

by 진꿈청 2024. 11. 10.

https://asfirstalways.tistory.com/359

 

 

`WebSocket`, `SockJS`, `STOMP`를 학습하고 직접 실습해보는 프로젝트를 구상을 했다.

개념을 학습하는 것과 직접 코드로 구현하는 것은 완전히 다른 영역이기에 실습해보는 것이 중요하다고 생각한다.

 

 

사용 예정 기술 스택

 

개발 언어 선정

개발 언어로는 Java를 선택했다.

`Kotlin`도 학습하면 좋겠지만, 제작할 채팅 서비스는
개념 학습 후 실습에 가까운 프로젝트이기에 아직 잘 모르는 `Kotlin`을 적용하기에는

너무 큰 Learning Curve가 될 것 같았기 때문이다.

 

Framework 선정

채팅 서비스를 제작하기 위해서는 당연히 Spring Framework를 활용했다.

(다른 Framework를 사용해본적도 없으며 개념 학습을 Spring 기반으로 했다.)

 

 

DB 선정

DB 선정에 있어서는 꽤 고민을 했다.

 

결론적으로 말하면 `MongoDB`와 `Redis`를 사용한다.

 

 

생각중인 구현 목록은

  • 유저 인증/인가 파트(Spring Security)
    • 유저 비밀번호 변경
    • Logout 필터에서 처리
    • Access Token Reissue 필터에서 처리
  • 일반 채팅 CRUD
    • 유저 채팅 입장시 유저별 코드 활용
      • SecureRandom
    • 유저 채팅방 조회
    • 유저 채팅방 나가기
    • 파일 채팅(CRUD)
    • 채팅 유저 추가
  • 채팅 메시지 CRUD(Transactional Outbox Pattern - Kafka) <- STOMP
    • 유저 접근 시 JWT 검증 진행
    • 채팅 조회
    • 채팅 CRUD
  • 실시간 경매 채팅(예정)
    • Redis 활용
      • Redis로 경매 종료시간 TTL 설정
      • TTL 종료시 관련 이벤트 발생하여 SpringBoot에서 처리

정도가 된다.

 

고민을 한 이유는 그냥 `STOMP`만 사용하는 것이 아니라

간단한 도메인을 갖더라도 어떤 도메인으로 동작하는 프로젝트를 만들고 싶었다.

 

그러다보니 유저 인증/인가부터, 채팅방 CRUD, 실시간 경매 채팅을 구상했고

이로 인해 생각보다 여러 기능들이 추가가 되었다.

 

유저와 채팅방이 추가됨에 따라 채팅에 강점을 갖는 `MongoDB` 보다는 `RDBMS`가 유리하고

`MongoDB`는 채팅에 강점을 갖는다.

 

2024.11.09 - [DB/MongoDB] - [MongoDB] MongoDB란?

 

[MongoDB] MongoDB란?

이번에 혼자 `WebSocket`, `SockJS`, `STOMP`에 관해 학습을 진행하며 채팅 서비스를 개발하는 것을 목표로 정했다. 이때 채팅 메시지에 관한 영구 저장소를 선택하기 위해 고민을 했는데 처음 떠오르

hdbstn3055.tistory.com

 

그리고 사용자 인증/인가 토큰 저장 및 추후 캐시 처리 및 실시간 경매를 위해서 `Redis`를 사용하므로,

장점만 생각하고 `DB`를 각각 사용하면 RDBMS, MongoDB, Redis 3가지 `DB`를 전부 사용해야 한다.

 

이는 너무 투머치라는 생각이 들었다.

 

또한, 결국 `STOMP`를 활용한 채팅 서비스 개발이 목적이며,
유저와 채팅방과 관련해서는 매우 복잡하게 구조화 하지는 않을 것이므로

`MongoDB`와 `Redis`만을 사용하기로 했다.

 

 

토이 프로젝트 메시지 처리 방식

앞서, 언급했듯이 프로젝트에는 `STOMP`를 사용한다.

 

학습을 위함도 있지만 `HTTP Polling` 방식과 `STOMP`의 기반이 되는 `WebSocket` 방식에 차이가 좀 있으므로 간단하게 집고 넘어가자. 

 

 

우선, 채팅 서버의 메시지 처리 방식은 크게 2가지가 존재한다.

 

 

HTTP Polling 방식

 

`HTTP Polling` 방식은 `WebSocket`과 다르게 `Connection`을 맺고 있지 않아도 되므로

서버 리소스를 상당히 절약할 수 있다. 또한, API 서버 개발만으로 간단하게 기능 구현이 가능하다.

 

그러나, 일정 주기로 메시지를 클라이언트에서 가져가는 방식이기에 다른 사용자가 작성한 메시지가 전달되는데
일정 시간 지연이 발생할 수 있다.

 

또한, 클라이언트 별로 Polling 되는 시점에 따라 서로 보고 있는 메시지가 다르기 때문에
실시간으로 보이는 채팅이 몇초 간 불일치하는 문제가 발생할 수 있다는 단점이 존재한다.

 

 

WebSocket 방식

 

대부분의 채팅 플랫폼에서 가장 많이 사용되는 메시지 전달 방식이다.

유저와 서버 간의 `Connection`이 맺어져 있기 때문에 메시지가 발생하는 즉시 전달한다는 장점이 있다.

 

하지만, 이로 인해 서버와 연결이 지속되어야 하므로 서버당 처리할 수 있는 클라이언트 수에 제한이 존재한다.

하지만, `HTTP Polling` 방식에서 발생하는 단점이 거의 완벽에 가까운 수준으로 발생하지 않는다고 한다.

 


 

이렇게 `HTTP Polling`과 `WebSocket` 모두 각각의 장단점이 존재한다.

하지만, `STOMP` 학습 목표와 아래와 같은 이유로 `WebSocket`을 선택하게 되었다.

 

바로 지속성과 실시간성이다.

 

`HTTP Polling` 방식은 일정 주기로 메시지를 클라이언트에서 가져가기에

채팅을 보기까지는 조금의 딜레이가 발생하여 채팅의 실시간성의 의미가 작아진다.

 

그렇다고 주기를 너무 짧게 가져가면 `HTTP` 통신이므로, 서버의 부하가 심해진다.

 

하지만, `WebSocket`은 이러한 `HTTP Polling` 방식의 지속성과 실시간성에 관한 단점이 발생하지 않는다.

또한, 사용자 입장에서 봤을 때 실시간이 중요한 채팅 서비스에서 메시지의 전달 지연은 부정적인 사용자 경험을 제공할 수 있다.

 

따라서, 메시지 처리 방식으로 `WebSocket`을 활용했고 거기에 `STOMP` 프로토콜을 더했다.

 

 

채팅 서비스에 MongoDB 활용

2024.11.09 - [DB/MongoDB] - [MongoDB] MongoDB란?

 

[MongoDB] MongoDB란?

이번에 혼자 `WebSocket`, `SockJS`, `STOMP`에 관해 학습을 진행하며 채팅 서비스를 개발하는 것을 목표로 정했다. 이때 채팅 메시지에 관한 영구 저장소를 선택하기 위해 고민을 했는데 처음 떠오르

hdbstn3055.tistory.com

 

이전의 `MongoDB란?` 포스팅에서 `MongoDB`가 뭔지 `MongoDB`의 장단점에 관해 알아보았다.

 

요악하자면 `MongoDB`는 RDBMS 보다 저장과 조회에서 성능적인 강점을 갖고,

`Schemaless`한 특성을 가져 다양한 형식의 데이터를 유연하게 저장 및 관리가 가능하다.

(즉, 쉽게 데이터 형태를 변화할 수 있다. 이는 채팅과 같이 기능의 추가가 빈번한 경우 큰 의미를 갖는다.)

 

따라서, 채팅 서비스의 영구 저장소로는 `RDBMS` 보다는 `NoSQL`이 더 우수하고,

다양한 `NoSQL` 중 확장에 유연하며 저장 및 조회에 강점을 갖는 `MongoDB`를 사용했다.

 

 

Transcational OutBox Pattern

왜 갑자기 `Transcational OutBox Pattern`을 사용하냐고 생각할 수 있다.

 

하지만, 이전 포스팅에서

 

2024.09.19 - [Infra/DevOps] - 분산 시스템에서 데이터를 전달하는 효율적인 방법 - 1

 

분산 시스템에서 데이터를 전달하는 효율적인 방법 - 1

이번 포스팅에서는 NHN 유튜브의 분산 시스템에서 데이터를 전달하는 효율적인 방법 강의를 보고 정리한 내용이다.  포스팅에서 다룰 내용데이터 전달 보장 방법론RDB를 사용하는 애플리케이션

hdbstn3055.tistory.com

 

`Transcational OutBox Pattern`에 관해 알아보았고 관련 내용을 같이 `FitTrip` 프로젝트를 진행한 팀원분이 구현하셔서

좋은 레퍼런스가 있었다.

 

따라서, `Scale-Out`에 큰 강점을 갖고 또 `Transcational OutBox Pattern` + `Polling` 방식의 사용으로,

`At Least Once Delivery`를 구현할 수 있도록 `Transcational OutBox Pattern`를 활용하였다.