Stomp + Kafka를 이용한 채팅 기능 개발하기 - (with Spring Boot) #1 (Kafka와 Stomp는 무엇일까?)

DevSeoRex·2023년 6월 12일
48
post-thumbnail

🤯 채팅을.. 만들라고요..?

이번에 진행했던 분양 플랫폼 프로젝트에서 팀원들과 온라인 킥오프를 하며 기능을 도출하고, 각 기능별 담당자를 배정하는 도중 우리 프로젝트의 핵심이자 큰 챌린지가 될 수 있는 채팅 기능을 누가 맡을지 서로 눈치게임을 하고 있었습니다.

팀 프로젝트를 하다보면 호기심과 열정으로 특정 기능을 가져가서 완성하지 못하면 민폐가 될까봐 망설인적이 많았었는데, 예전 프로젝트를 되돌아봤을때 할만하겠다 쉽겠다 생각하고 마음편히 만들었던 기능은 없었다는 것이 기억나서 용감하게 채팅 기능을 제가 담당하게 되었습니다.

채팅 기능을 구현하기 위해서 관련 레퍼런스들을 찾아보고 어떻게 시스템을 구성할지 생각하다 보니 많은 키워드들이 스쳐지나갔습니다. Kafka, Stomp, MongoDB, Web Socket 중요한 건 이중에서 써본것은 하나도 없었다는 것입니다.

😲 하나하나 따져서 기술을 선정하자!

일단 어떤 기술들을 채택할지 선택해야 하는데, 관련 지식이 없으니 어떤 기술의 조합을 가지고 가야할지 고민조차 할 수 없었습니다. 따라서 비슷한 기술은 서로 비교하고, 그 중에서 우리 프로젝트와 어울리는 기술을 채택하기로 결정하고 학습을 시작했습니다.

Web Socket vs Stomp

🧐 Web Socket은 무엇일까?

웹 소켓은 HTML5 표준 기술로, HTTP 환경에서 클라이언트와 서버 사이에 하나의 TCP 연결을 통해 실시간으로 전이중 통신을 가능하게 하는 프로토콜입니다.

웹 소켓이 개발되기 이전에는 Polling이나 Long Polling 방식으로 실시간은 아니지만 그에 준하도록 구현해서 문제를 해결해왔습니다.

  • Polling
    • 클라이언트가 일정 주기로 서버에게 필요한 데이터를 요청하는 방식입니다.
    • 가장 쉬운 방식이지만, 서버에 부담을 주게 됩니다.
  • Long Polling
    • 서버는 클라이언트에게 즉시 응답을 주지 않는다는 특징이 있습니다.
    • 폴링이 의미없이 서버의 리소스를 낭비하는 것처럼 보여서 롱폴링이 유리해 보일 수 있지만, 경우에 따라 롱 폴링 방식이 폴링 방식보다 서버에 부하를 더 주는 경우도 있습니다.

웹 소켓이 등장한 이후부터는 클라이언트와 서버간의 실시간 통신이 가능하게 되었습니다.

HTTP 통신에서는 연결을 지속하지 않고, 클라이언트가 서버로 단방향 요청만 가능하게 구성되어 있었습니다.

웹 소켓이 등장한 이후부터는 클라이언트와 서버간 연결을 지속적으로 유지하고 서버도 클라이언트로, 클라이언트도 서버로 데이터를 보낼 수 있게 됨으로서 양방향 통신을 할 수 있는 시대가 열렸습니다.

웹 소켓은 요청과 응답 개념이 아닌 서로 데이터를 주고 받는 형식을 취하고 있습니다.

그렇다면 웹 소켓만으로는 채팅기능을 만들 수 없을까요?

웹 소켓만으로 채팅을 만드는 것은 가능합니다. 그렇다면 왜 Stomp와 비교해서 기술을 선택하려 했을까요?

😈 Stomp는 무엇일까?

웹 소켓 프로토콜은 두 가지(텍스트, 바이너리) 유형의 메시지를 정의하고 있지만 메시지의 내용까지는 정의하고 있지 않습니다.

Stomp는 메세지 전송을 효율적으로 하기 위해 등장한 프로토콜입니다. 기본적으로 pub/sub 구조를 따르고 있기 때문에 메시지를 전송하고 메시지를 받아 처리하는 부분이 명확하다는 장점이 있습니다.

Stomp를 이용해 채팅 시스템을 개발한다고 한다면 세가지의 크게 두가지 행동이 있다고 볼 수 있습니다.

  • 채팅방 입장 : 현재 입장한 채팅방의 번호를 구독한다.
  • 채팅방에서 메시지를 보내거나 받기 : 구독한 채팅방에서 메시지를 보내거나 받아볼 수 있다.

Stomp를 이용하면 어떤 점이 좋을까요?

Stomp를 사용해 채팅 기능을 개발한다면 아래와 같은 장점을 가집니다.

  • 채팅 엔드포인트를 Spring Security를 이용하여 권한을 제어할 수 있다.
    • ex) 운영자만 입장 가능한 채팅방
  • Publisher으로 부터 전달 받은 메시지를 Subscriber로 전달해줄 때 중간에서 메시지를 주고 받게 해주는 메시지 브로커를 사용할 수 있다.

Stomp를 사용하면 기본적으로 In-Memory Message Broker를 사용하게 되는데, 이로인해 생기는 여러가지 문제가 있습니다. 다만 이 부분은 RabbitMQ, Kafka, Active MQ와 같은 외부 브로커를 사용함으로서 문제를 해결할 수 있기 때문에 큰 제약이라고 보긴 어렵습니다.

🥴 그렇다면 Stomp vs WebSocket 어떤 것을 선택할까요?

지금 제가 구현해야 하는 기능은 채팅 기능입니다.

채팅을 초점에 두고 생각해보면, WebSocket으로 채팅을 구현한다면 어떤 채팅방에 현재 누가 접속중인지 알아야하고, 채팅방에 포함된 사용자에게 모두 메시지를 보내야 하기 때문에 채팅방마다 세션을 관리해야 하는 번거로움이 있습니다.

Stomp로 채팅을 구현한다면, 사용자가 채팅방에 접속했을때 해당 채팅방을 구독하기만 한다면 누가 접속중인지 따로 관리하지 않아도 메시지를 보낸 사용자가 포함된 채팅방의 모든 사람에게 메시지가 갈 수 있다는 강점을 가지고 있습니다.

이런 부분에서 채팅 기능에 조금 더 부합하는 기술은 Stomp라고 판단하여 Stomp를 채택하게 되었습니다.

Kafka vs RabbitMQ

메시지 큐를 떠올리면 대표적으로 Kafka와 RabbitMQ를 생각할 수 있습니다.

그렇다면 둘은 어떤 차이가 있는지 지금부터 살펴 보겠습니다.

🙂 What is RabbitMQ?

RabbitMQ는 대표적인 메시지 브로커 입니다.
메시지 브로커란 publisher가 생산한 메시지를 메시지 큐에 저장하고, 저장된 데이터를 consumer가 소비할 수 있도록 중간 다리 역할을 해줍니다.

consumer가 큐에서 데이터를 가져가게 되면, 메시지 처리 후 짧은 시간내에 데이터가 삭제된다는 점을 주의해서 사용해야 합니다. 전통적인 메시지 브로커의 형태를 따르고 있으며, 이러한 형태는 앱의 트래픽이 증가하여도 수평적으로 확장하는 데에 어려움을 주게 됩니다.

이벤트 메시지가 성공적으로 전달되었다고 판단되면, 메시지가 큐에서 삭제되기때문에 다시 이벤트를 재생하기 어렵다는 단점도 존재합니다.

👻 What is Kafka?

Kafka는 대표적인 이벤트 스트리밍 플랫폼입니다.
메시지 브로커와 이벤트 스트리밍 플랫폼 모두 이벤트를 수신하고, 이것을 consumer에게 전달하는 데에 목적이 있다는 것은 같습니다. 하지만 이 둘의 작동 방식은 큰 차이가 있습니다.

이벤트 스트리밍 플랫폼은 이벤트가 생성되면, 레코드 로그를 streamer에 기록하게 됩니다.
consumer가 topic을 가져간 후에도 이벤트 스트림에서 로그를 계속 유지하기 때문에 에러나 기타 문제가 생겼을 경우 이벤트를 재생할 수 있다는 강력한 장점이 있습니다.

이벤트 스트리밍 플랫폼은 전통적인 메시지 브로커에 비해 좀 더 유연하고 느슨한 결합을 가져갈 수 있게 되었습니다. 따라서 격리와 확장이 비교적 쉽다는 장점도 가지고 있습니다.

Kafka는 Zookeeper가 실행중이여야 사용할 수 있습니다. Zookeeper는 분산 코디네이션 시스템을 제공합니다. Kafaka Cluster의 리더를 발탁하는 방식도 Zookeeper가 제공하고 있습니다.

메시지 브로커는 이벤트 브로커가 될 수 없지만, 이벤트 브로커는 메시지 브로커 역할을 할 수 있습니다.

🥴 그렇다면 Kafka vs RabbitMQ 어떤 것을 선택할까요?

사이드 프로젝트로 만든 플랫폼 서비스이기 때문에, 사용자가 백만명이상 또는 엄청난 트래픽이 몰려서 그 트래픽을 받아내야 하는 상황은 아니라고 판단이 들었습니다.

그래도 이번 프로젝트의 목적인 고가용성의 설계를 가진 애플리케이션을 만들어보자는 목표에 부합하기 위해서는 트래픽이 많고, 장애가 생겼을때 대응할 수 있는 포인트가 조금 더 명확한 Kafka를 사용하기로 결정하였습니다.

RabbitMQ도 exchange를 통한 pub/sub 구조를 구현할 수 있고, 충분히 채팅 시스템을 구현하는 것에는 지장이 없지만 추후 트래픽이 몰릴거라는 가정 하에서는 Kafka가 조금 더 유연할 것으로 생각했습니다.

이 프로젝트를 추후 MSA 아키텍처로 변경하기 위해서도 느슨한 결합을 가져가는 것이 좋다고 판단이 들었습니다.

MongoDB vs MySQL

채팅방의 채팅 내용을 쓰고, 읽는 작업을 하기 위해서 기존에 사용하는 MySQL을 계속 사용할지 MongoDB를 채팅전용 DB로 사용해야 하는지에 대한 고민이 생겼습니다.

결론부터 말씀드리면, 순수한 채팅방에 대한 데이터는 MySQL을 사용하고, 채팅 기록은 MongoDB를 사용하기로 결정하였습니다. 지금부터 이유를 말씀드리겠습니다.

MongoDB는 NoSQL의 한 종류이기 때문에 RDB보다 더 빠른 읽기 쓰기 성능을 가지고 있습니다.
채팅 내용은 언제든지 바뀔 수 있고, 많은 양의 데이터가 수시로 읽고 써진다는 특징이 있습니다. 이런 부분에서 MongoDB를 이용해서 채팅 데이터를 관리해주는 것이 성능적으로 이점을 가질 것이라고 생각했습니다.

채팅방 부분만 MySQL을 이용해서 따로 관리하는 이유는 다음과 같습니다.

분양 플랫폼 서비스에서 분양글의 PK(고유키)와 회원의 PK는 어떤 회원의 채팅방 리스트를 조회할때 꼭 필요한 정보입니다. 결론적으로 회원이 채팅방 목록을 보려고 할때 JOIN 연산이 불가피하므로, MySQL을 이용해 채팅방 정보를 유지하기로 결정하였습니다.

회원이 채팅방 리스트를 조회할때 한번만 조회 쿼리가 나가기때문에 수시로 읽고 쓰는 채팅 내용보다는 훨씬 가벼운 작업이기 때문에 관계형 데이터베이스의 강점은 살리고, NoSQL의 강점은 따로 가져가는 결정을 하였습니다.

🥳 다음으로..!!

처음 만들게 된 채팅 기능이라, 기술 선정부터 테이블 설계 기능 구현까지 많은 이슈와 에러를 겪으면서 만들었습니다. 이렇게 힘들게 만든 기능이라 조금 더 애착이 가기도 합니다.

오늘은 2가지 또는 3가지 정도의 선택지에서 어떤 기술을 선택하고, 왜 그 기술을 선정했는지에 대한 이유를 다뤄 보았습니다. 다음 포스팅부터는 환경을 설정하고 하나하나 기능을 구현해보겠습니다.

오늘도 읽어주셔서 감사합니다.

다음 시리즈 게시물로 이동
Stomp + Kafka를 이용한 채팅 기능 개발하기 - (with Spring Boot) #2 (Kafka 설치 + MongoDB & Stomp 설정)
게시물로 이동 ->

🙇

참고한 레퍼런스

12개의 댓글

comment-user-thumbnail
2023년 6월 12일

평소 관심있던 부분이었는데 너무 정리가 깔끔하네요-! 좋은 글 작성해 주셔서 감사합니다 ㅎㅎㅎ

1개의 답글
comment-user-thumbnail
2023년 6월 13일

개판데렉서님

1개의 답글
comment-user-thumbnail
2023년 6월 20일

개판데서

1개의 답글
comment-user-thumbnail
2023년 9월 5일

잘 읽었습니다.

1개의 답글
comment-user-thumbnail
2024년 2월 14일

안녕하세요 너무 잘읽었습니다! 기존 프로젝트에 해당 게시글 전체를 적용시켰는데 mysql버전 문제인지 기본값도 상승을 못한다던가 mysql에 에러가 자꾸나오네요 ㅠ 혹시 mysql 및 jpa설정과 관련된 부분은 어딘지 알려주실 수 있을ㄹ까요? 깃헙에 있는 코드를 가져온겁니당

1개의 답글