되돌아보기
지금까지 채팅 프로그램을 구현하면서 WebSocket, SockJS, STOMP를 하나씩 적용해 보았다. 단순히 1:1 채팅을 넘어서 여러 사람이 함께 채팅방을 만들고, 채팅을 할 수 있도록 구성했다.
하지만 지금의 프로젝트는 몇 가지 문제가 있다.
먼저 스프링 부트 애플리케이션을 재시작하면 채팅 정보가 사라지는 문제가 있다. 이는 메시지 큐, 메시지 브로커가 In-Memory 방식으로 동작하기 때문이다.
In-Memory 방식으로 인한 문제는 더 있다. 이용자의 수가 많아지면 처리해야 하는 데이터가 많아질 것이고, 내장된 SimpleBroker
는 스프링 부트가 실행되는 곳의 메모리를 잡아먹게 되므로 서버의 부담이 커질 수밖에 없다.
마지막으로 (지금 당장은 아니지만) 서버를 확장하게 된다면 여러 서버로 동시에 메시지를 전송할 수 없는 문제가 있다. 즉 메시지 송수신 서비스를 외부에서 동기화할 필요가 있다.
문제를 확인했으니 이제는 조금 더 나아가서 RabbitMQ라는 메시지 브로커를 사용해 볼 것이다. 그 전에 지금까지 적용한 기술에 대해 왜 사용했는가를 간단히 정리해 보고자 한다.
기술의 사용 이유
-
WebSocket
- 페이지 refresh 없이도 내가 보낸 메시지, 상대방의 메시지를 받을 수 있어야 한다.
- 이를 위해서는 서버 연결이 끊기지 않고 지속적으로 이루어져야 한다.
- WebSocket은 한 번 HTTP를 통해 연결하면, 그 연결을 계속 유지한다.
-
SockJS
- WebSocket은 브라우저마다 지원 현황이 다르다.
- SockJS는 브라우저에서 WebSocket을 지원하지 않거나, 네트워크 Proxy 제약 등으로 인해 WebSocket을 사용할 수 없는 경우에 Fallback 옵션을 제공한다.
- 즉 Websocket을 사용할 수 없는 환경에서도 SockJS 프로토콜을 통해 WebSocket API를 사용할 수 있다.
-
STOMP
- WebSocket은 메시지 형식이 따로 정해져 있지 않아서 직접 세션을 관리하고, 메시지 전송을 핸들러를 통해 조정할 필요가 있다.
- STOMP를 사용하면 정해진 규칙(Frame)으로 메시지를 전송할 수 있다.
- 또한 Pub/Sub 구조로 간단히 메시지를 선택적으로 수신할 수 있다.
RabbitMQ
RabbitMQ는 서버 간 메시지를 전달해주는 오픈 소스 메시지 브로커이다.
- RabbitMQ는 메시지를 많은 사용자에게 전달하거나, 요청에 대한 처리 시간이 길 때, 요청을 다른 API에 위임하고 빠른 응답이 필요할 때 많이 사용한다.
- AMQP라는 메시징 프로토콜을 사용한다.
AMQP
- AMQP는 인스턴스가 데이터를 서로 교환할 때 사용하는 방법이다.
- MQ를 오픈 소스에 기반한 표준 프로토콜로 만든 것이다.
RabbitMQ 개념
-
Producer
- 요청을 보내는 주체이다.
- 보내고자 하는 메시지를 Exchange에
publish
한다.
-
Consumer
- Producer로부터 메시지를 받아서 처리하는 대상이다.
-
Exchange
- Procuder로부터 전달 받은 메시지를 어떤 Queue에 보낼지 결정한다.
-
Queue
- Consumer가 메시지를
consume
하기 전까지 메시지를 보관하는 장소이다.
-
Binding
- Exchange와 Queue 사이의 관계를 말한다.
- 모든 메시지는 Exchange에서 먼저 수신하게 되는데, Exchange 타입과 Binding 규칙에 따라 적절한 Queue로 메시지를 전달한다.
RabbitMQ를 사용했을 때의 장점
You can (optionally) use message brokers (such as RabbitMQ, ActiveMQ, and others) to manage subscriptions and broadcast messages.
구독을 관리하고 메시지를 전달하는 데 선택적으로 메시지 브로커(RabbitMQ, ActiveMQ 등)를 사용할 수 있다.
- 채팅 관리를 외부로 빼서 서버의 부담을 줄일 수 있다.
- 다양한 형태의 구독 메시지를 설정할 수 있다.
- 비동기 메시징이 가능하다.
Exchange의 4가지 타입
RabbitMQ는 AMQP를 구현했기 때문에 Exchange Type이 미리 선언된 이름으로 정의되어 있다.
-
Direct
- 바인딩 된 Queue 중에서 메시지의 라우팅 키와 매핑되어 있는 Queue로 메시지 전달 (1:1)
-
Fanout
- 메시지의 라우팅 키를 무시하고 Exchange에 바인딩 된 모든 Queue에 메시지 전달 (Broadcast)
-
Topic
- Exchange에 바인딩 된 Queue 중에서 메시지의 라우팅 키가 패턴에 맞는 모든 Queue에게 메시지를 전달 (Multicast)
-
Headers
- 라우팅 키 대신 메시지 헤더에 여러 속성들을 더해 속성들이 매칭되는 큐에 메시지를 전달
RabbitMQ vs. Kafka
RabbitMQ와 Kafka는 메시지를 전달하는 역할로 많이 사용된다.
-
RabbitMQ
- 메시지 브로커로써 메시지를 전달하고 받을 때 메시지를 보관하지 않고 삭제한다.
- 많은 용량을 처리하지 못하지만 다양한 형태의 메시지 라우팅을 RabbitMQ 브로커 안에서 구성할 수 있다.
-
Kafka
- 이벤트 브로커로써 메시지를 수신했을 때 메시지를 ‘정책 단위’만큼 저장하고, 대용량의 처리가 가능하다.
- 메시지 라우팅을 하려면 외부에서 Topic을 여러 개 생성하고, 라우팅 로직을 직접 작성해야 한다.
RabbitMQ는 메시지를 조직적으로 라우팅하고 싶을 때,
Kafka는 대용량 처리, 메시지 보관 등 빅데이터를 처리할 때 주로 사용한다.