1. 개요
실무에 적용해본 RabbitMQ가 무엇인지를 알고, 관련된 개념들도 함께 정리해보자.
2. RabbitMQ 무엇인가요?
AMQP를 구현한 오픈소스 메시지 브로커.
3. AMQP 란 무엇인가요?
Advanced Message Queueing Protocol의 약자로 최적화된 방식의 메시지 큐잉 프로토콜을 말한다. 그럼 최적화된 방식은 뭘까? 바로 메시지 브로커를 사용해 클라이언트 간의 메시지 전송을 표준화한 프로토콜이다.
메시지 브로커
메시지 브로커의 사전적 의미는 "메시지를 중개하는 사람"이다. AMQP에서 말하는 메시지 브로커는 송신자(Publisher)와 수신자(Consumer) 사이에서 메시지를 안전하고 효율적으로 전달해주는 중간자를 의미한다.
클라이언트는 Consumer만이 아니다. 메시지 브로커 입장에서는 Publisher, Consumer 모두 클라이언트이다.
Publisher
브로커와 연결을 맺고, 메시지를 발행하는 클라이언트
Consumer
브로커와 연결을 맺고, 메시지를 수신하는 클라이언트
중간자가 있다면 뭐가 달라지나요??
메시지 브로커와 같은 중간자가 있다면 송신자와 수신자의 통신 방식은 어떻게 될까?
송신자는 수신자를 직접 찾아갈 필요가 없고, 수신자가 언제 받을 수 있는지 체크할 필요도 없다. 그냥 보내고 싶을때 중간자에게 메시지를 전송하면 된다. 수신자에게 전달하는 건 중간자가 알아서 처리하기 때문이다.
수신자도 마찬가지이다. 메시지를 누가, 언제 보낼 예정인지 알 필요가 없고, 메시지를 받을 준비도 필요 없다. 나에게 온 메시지가 있다면 중간자에게 바로 보내달라고 요청해놓으면 되기 때문이다. 택배가 도착하면 도착 알림 메시지가 오는것처럼 말이다. 참고로 수신자가 메시지를 받는 방식은 두가지이다. 수신자가 메시지 브로커에게 주기적으로 메시지를 확인하는 Pull 방식, 메시지가 오면 브로커가 수신자에게 메시지를 즉시 전달하는 Push 방식이 있다. 이를 '소비 모델'이라고 한다.
소비 모델
메시지 브로커를 통해 소비자가 메시지를 가져가는 전략을 말한다.
Push 방식이 더 좋은거 아니야? 왜 굳이...Pull??
수신자가 메시지 브로커에서 메시지를 확인하는 Pull 방식보다는 브로커가 즉각, 알아서 수신자에게 메시지를 전달하는 Push 방식이 효율적으로 보인다. 당연히 속도도 빠를거고, 메시지 브로커에게 '확인'하는 단계가 없기때문에 네트워크 리소스 측면에서도 효율적으로 보인다. 하지만, 상황에 따라서 Pull 방식이 좋은 케이스도 있다.
집이 좁아요...
전세사기를 당해 3평짜리 원룸으로 이사했다고 가정해보자. 이를 불쌍하게 여긴 가족, 친구, 지인들이 음식, 아이스크림, 전자제품 등을 막 보내기 시작했다. 처음엔 너무 감사했지만, 냉장고가 꽉 차 음식과 아이스크림을 보관할 수가 없고, 전자제품은 더 이상 집에 들일 수 만큼 비좁았다. 음식과 아이스크림은 곧 상해버렸고, 전제제품은 집 밖에 내놨다가 비를맞고 고장이 나버렸다.
만약, 택배 회사에 큰 창고가 있고, 내가 필요할때마다 택배 회사로 연락해 내 집이 수용할 수 있을 만큼만 전달받으면 어떨까? 내 집에 수용할 수 없는 전자제품, 음식, 아이스크림은 모두 택배회사에 안전하게 보관될것이기 때문에, 버려지지 않을것이다.
그렇다. 일반적으로 메시지를 즉시 받아야 하는 상황이 있는 반면, 수신자의 환경에 따라 메시지를 일정량만 받아야 하는 상황도 있다. 특히 대량의 데이터라면 수신자는 데이터를 한번에 처리하는 것이 매우 부담될것이다.
바빠요...
만약 우리가 보낸 물건을 택배회사에서 모아서가 아닌, 실시간/즉각적으로 처리해주면 어떻게될까? 예를들어 필자가 택배 발송 신청을 하자마자 택배회사가 가져가고, 택배회사에서 받자마자 수신자에게 전달하는 것이다.
그럼 수신자 입장에서는 아주 빨리 택배를 전달받을 수 있다. 그런데, 1시간동안 1000명의 사람이 동일한 수신자에게 택배 발송 신청을 하면 어떨까? 택배회사에 물건이 도착하지마자 택배 기사를 불러 물건을 배송시킬것이고 수신자에게 1000번의 발송이 필요하게 된다. 택배 기사는 죽어날것이다. 만약 한 시간 단위로 수신자가 택배회사로 택배 발송 요청을 했다면, 1시간동안 모인 1000개의 택배를 1번의 발송으로 처리할 수 있게 된다.
결국 수신자가 실시간 데이터를 감당할 수 있느냐에 따라 권장되는 방식이 달라지는 것이다.
RabbitMQ vs Kafka
RabbitMQ 는 AMQP 구현체이지만 Kafka는 아니다. Kafka는 Pull 기반 소비 모델을 채택한 분산 로그 시스템으로, 큐가 아닌 로그파일을 기반으로 데이터를 가져간다. 메시지를 큐에서 바로 소비하고 사라지는 방식이 아닌, 디스크에 append-only log로 저장하면, 클라이언트는 이 로그파일의 offset 기준으로 데이터를 읽어간다. 둘 다 브로커라는 중간자를 사용하여 데이터를 처리한다는 점에서 RabbitMQ와 함께 언급되곤 한다.
기본 처리 방식은 곧 내부 설계를 말한다. RabbitMQ는 Push 방식, 즉 실시간 처리에 특화 설계되어있고, Kafka는 Pull 방식,대용량 처리에 특화 설계되었다. 때문에 실시간 처리가 중요하다면 RabbitMQ를, 실시간 처리보다는 통계 데이터와 같이 대용량 데이터 처리가 중요하다면 Kafka를 선택하는 것이 좋다고 생각한다.
필자의 경우 실시간 처리가 중요했고, 데이터의 양은 1분에 10건 정도였기 때문에 RabbitMQ를 선택했다.
메시지 전송 표준화 / 구조
처음 AMQP를 "메시지 브로커를 이용해 클라이언트간의 메시지 전송을 표준화한 프로토콜"이라 했다. 표준화는 바로 Exchange, Queue, Binding 구조를 통해 표준화시켰다.
Exchange
발행자가 보낸 메시지를 받아서, Binding 규칙에 따라 Queue로 전달.
Binding
Exchange와 Queue를 연결하는 규칙
Queue
메시지를 저장하는 버퍼로, 소비자가 메시지를 읽고 ACK를 회신할때까지 보관
AMQP 동작 흐름
1) Producer가 메시지를 메시지 브로커의 Exchange로 전달
2) Exchange가 Binding 규칙에 따라 메시지를 Queue에 전달
3) Queue에서 메시지를 가져와 Customer에게 전달
4) 처리 완료 후 ACK(확인 응답)를 회신
5) Queue에 있는 해당 메시지를 삭제
AMQP의 특징
ACK 검증
소비자 <-> 메시지 브로커 사이의 확인 응답으로 메시지를 소비자가 잘 처리했는지를 보장한다.
라우팅 유연성
다양한 Exchange 타입으로 복잡한 메시지 흐름을 구현할 수 있다.
Confirm 모드
발행자 <-> 메시지 브로커 사이의 확인 응답으로 메시지가 브로커에 잘 도착했는지를 보장한다.
Transaction 모드
발행자가 여러 메시지를 보낼 때, 원자적으로 처리하기 위한 모드로, 메시지 발행 작업의 원자성을 보장한다.