본문 바로가기
Framework and Tool/MQ

RabbitMQ vs Apache Kafka

by ocwokocw 2022. 3. 24.

- 원글: https://www.cloudamqp.com/blog/when-to-use-rabbitmq-or-apache-kafka.html

- 개요

두 메시지큐는 queue나 topic을 통해 생산자와 소비자간의 메시지를 전송한다. 메시지는 어떤 것이든지 될 수 있는데, 웹사이트에서 일어나는 이벤트에 관한 정보라던가 다른 Application의 이벤트를 발생시키는 간단한 메시지와 같은 형태일 수도 있다.
 
이런 종류의 시스템은 다른 component를 연결 시키거나, 마이크로 서비스를 구축하거나, data의 실시간 스트리밍 또는 원격 작업자에게 특정 작업을 전달하는데 적합하다.
 
그래서 언제 Kafka를 사용하고 또 어떨 때 RabbitMQ를 사용하는가?

- Message handling

Kafka가 다른 메시징 시스템과 차별화 되는 점은 메시지 큐가 영속성을 갖는다는점이다. 전송된 데이터는 설정된 기간이나 크기 제한에 도달하기 전까지는 저장된다. 따라서 한번 소비 되어도 설정한 제한을 초과하지 않는 이상은 메시지가 사라지지 않는다. 여러 번 소비되거나 재처리될 수 있으며 이는 설정으로 조정가능하다.
 
RabbitMQ 에서 메시지는 수신하는 application 이 연결되거나 queue에서 메시지를 수신할때까지 저장된다. client는 메시지를 수신하거나 메시지 처리를 끝내면 메시지를 ack(acknowledge - 확인) 처리할 수 있다. 앞에서 말한 두 경우 모두 메시지가 ack 처리되면 queue에서 사라진다.
 
Kafka에서 재처리를 할 때에는 고려해야할 사항이 있다. 한번 일어나야 하는 이벤트를 여러 번 재처리를 하는 경우(ex - 소비자의 주문을 여러번 발행시키는 경우) 는 특수한 경우라면 모르겠지만 일반적인 시나리오에서는 적합하지 않다고 할 수 있다. 재처리는 버그가 있어서 새로운 버전의 배포가 필요하고 메시지의 일부 또는 전체를 재처리 해야하는것과 같은 경우라면 유용한 case가 될 수 있을것이다.

- Protocol

RabbitMQ는 AMQP 0.9.1을 기본적으로 구현하는 몇몇 표준 프로토콜(ex - AMQP, MQTT, STOMP 등)을 지원한다. 이런 표준화된 메시지 프로토콜을 사용하면 RabbitMQ 브로커를 AMQP 기반의 브로커로 변경하는것과 같은 작업이 가능해진다.
 
Kafka는 자신만의 프로토콜을 사용 하므로 쉽게 제거되거나 교체될 수 없다.
 
AMQP의 최신버전은 공식적으로 지원되는 0.9.1 버전과 비교해서 달라진점이 많다. 하지만 RabbitMQ가 AMQP 0.9.1 Spec을 벗어날 가능성은 거의 없는데, 2011.10.30에 배포된 1.0 버전의 프로토콜이 개발자들로 부터 지지를 받지 못했기 때문이다.

- Routing

Kafka는 매우 단순한 routing 접근법을 취하고 있으며 RabbitMQ는 메시지 routing 과 관련해서 많은 옵션을 제공하고 있다.
 
RabbitMQ의 가장 큰 장점은 유연하게 메시지 routing을 할 수 있다는 점이다. 코드를 새로 작성하지 않아도 직접적으로 혹은 정규 표현식 기반으로 메시지를 특정 queue로 보낼 수 있다. RabbitMQ는 4 가지 라우팅 옵션을 제공한다.
 
  • Direct exchange: "routing key"에 정확히 매칭되는 모든 queue로 메시지를 routing
  • Fanout exchange: exchange에 바인딩된 모든 queue에 메시지 broadcast
  • Topic: Direct 처럼 routing key 를 사용하지만 정확한 매칭이 아닌 wildcard 매칭을 이용
  • Header exchange: Topic exchange와 비슷하지만 routing key 대신 header 값에 기반하여 메시지를 routing
 
Kafka는 routing을 지원하지 않는다. Kafka의 topic 들은 순번을 변경할 수 없는 메시지를 포함한 partition 들로 나뉜다. 모든 메시지를 하나의 topic으로 전송하고 소비자 그룹이 다른 offset을 구독하도록 하는 방식으로 RabbitMQ에서 routing 하는 것을 대신해서 영속적인 topic과 소비자 그룹을 사용한다.
 
Kafka stream의 도움을 받으면 동적 routing을 생성해서 event를 동적으로 topic으로 보낼 수 있지만 기본적인 기능은 아니다.

- Message Priority

RabbitMQ 는 우선순위 queue를 지원하는데 queue가 우선순위의 범위를 갖도록 지정할 수 있는 방식이다. 각 메시지가 발행될 때 우선순위가 설정된다. 메시지의 우선순위에 따라 적절한 우선순위 queue로 할당된다. 만약 DB를 매일 자동으로 backup하는 작업이 RabbitMQ가 추가된다고 가정해보자. 만약 backup을 수동으로 실행해야할 때가 있다면 이런 작업이 queue에 추가될때는 높은 우선순위를 가져야 할 것이다.
 
Kafka에서는 메시지가 우선순위 수준이나 순서에 따라 전송되게 설정할 수 없다. kafka의 모든 메시지는 순서대로 저장되고 전송된다.

- Acknowledgment (Commit or Confirm)

Acknowledgment는 승인, 즉 전송된 메시지의 수신이나 처리됨을 나타내기 위한 process 간의 전송되는 신호이다.
 
Kafka나 RabbitMQ 모두 발행된 메시지가 안전하게 broker에 도달했는지를 보장해주기 위해 producer acknowledgement 를 지원한다.
 
node가 메시지를 consumer에게 전송할 때 메시지가 consumer가 처리(적어도 수신)한것으로 간주해야하는지 여부를 결정해야한다. client는 메시지를 수신하거나 메시지를 완전히 처리했을 때 ack(승인) 처리할 수 있다.
 
RabbitMQ는 메시지가 한번 전송되면 메시지가 전달된것으로 간주하거나, consumer가 직접 acknowledgement 처리를 할 때 까지 대기할 수 있다.
 
Kafka는 partition의 각 메시지마다 offset을 관리한다. commit된 위치는 저장된 마지막 offset 이다. 이렇게 저장된 마지막 offset은 프로세스가 실패해서 다시 시작되면 복구하는 지점이 된다. Kafka의 consumer는 주기적으로 offset을 자동 commit 하거나 commit된 위치를 직접 제어하도록 선택할 수 있다.
 
RabbitMQ client는 메시지 처리를 실패했을 때 nack(nagative acknowledgement) 처리도 할 수 있다. 이 메시지는 마치 새로운 메시지 였던것처럼 queue로 다시 돌아갈 수 있는데 consumer 쪽의 일시적인 문제로 인한 실패와 같은 처리를 할 경우 유용하다.

- How to work with the queues?

RabbitMQ의 queue는 비어있을 때 가장 빠른 반면 kafka는 대규모 메시지를 저장하거나 분산하도록 설계되어있다. Kafka는 아주 적은 오버헤드로 대용량 데이터를 유지한다.
 
RabbitMQ를 사용해본 사람들이라 해도 lazy queue 기능을 인지하는 사람은 거의 없다. Lazy queue는 약간의 처리시간을 희생하는대신 RAM 사용량을 최소화하고 메시지를 자동으로 disk에 저장하는 기능이다. 해당 글의 필자는 경험적으로 lazy queue가 더 나은 예측 성능으로 안정적인 클러스터를 생성한다고 말하고 있다. 만약 한번에 많은 메시지를 전송하거나(ex - Batch job), consumer가 메시지를 발행하는 쪽의 속도를 맞출 수 없다면 lazy queue를 활성화하는것도 하나의 방법이 될 수 있다.

- Scaling

Scaling은 시스템의 용량을 늘리거나 줄이는 과정을 의미한다. RabbitMQ와 Kafka는 다양한 방법으로 scale을 수행하는데, consumer의 수나 broker power를 조절하거나 시스템에 node를 더 많이 추가하기도 한다.
 
- consumer scaling
 
RabbitMQ에서 메시지를 소비하는 속도보다 발행하는 속도가 더 빠르면 queue가 점점 차기 시작해서 결국 메모리가 다 소진될것이다. 이런 경우에 메시지를 소비하는 consumer의 수를 늘려야 한다. RabbitMQ의 각 queue는 많은 consumer를 가질 수 있는데 이런 consumer들은 queue에서 메시지를 소비할 때 경쟁상태에 빠질 수 있다. 메시지 처리는 모든 활성화된 consumer 들에게 퍼지므로 단순히 consumer를 추가하거나 제거해서 RabbitMQ의 scaling을 확장 및 축소할 수 있다.
 
Kafka 에서는 topic partition을 이용하여 consumer를 분산하는데, 그룹의 각 consumer는 하나 이상의 partition에 할당된다. partition 매커니즘을 사용하여 비즈니스 키(ex - user id, 위치) 로 분류된 다양한 message 묶음 들을 각 partition으로 전송할 수 있다.
 
- scaling broker
 
RabbitMQ 에서는 수평 방식(서버나 기기의 대수를 늘리는 방식)으로 확장을 하면 반드시 더 나은 성능을 보장해주지 않는다. 수직 방식(RAM, CPU등의 Spec UP)으로 확장하는것이 성능향상에 도움이 된다. 수평 방식도 가능하지만 node간의 클러스터링을 세팅해줘야 하므로 설정 속도를 저하시킬 수 있다.
 
Kafka 에서는 클러스터에 노드를 추가하거나 topic에 partition들을 추가하여 scaling을 할 수 있다. 이런 방식이 때로는 기존 서버에 CPU나 memory를 추가하는 방식보다 더 나은 경우가 있다.
 
많은 블로그나 사람들이 scaling 측면에서 Kafka가 얼마나 좋은지를 논하고 있다. Kafka가 RabbitMQ 보다 강점이 있는 이유는 구매할 수 있는 서버나 기기의 크기(Spec)에는 제한이 있기 때문이다. 그러나 왜 broker를 사용하는가라는 점을 생각해봐야 한다. Kafka나 RabbitMQ 모두 큰 문제없이 메시지를 다룰 수 있으며 대부분의 경우 RabbitMQ의 용량을 다 소진해버릴 만큼의 규모를 다루는 경우는 거의 없기 때문이다.

- Log compaction

Kafka에만 존재하는 log 압축 전략은 언급할 가치가 있다. Log 압축은 단일 topic partition을 위한 queue내의 메시지 key에 대한 마지막 값을 유지하는것을 보증해준다. Kafka는 메시지의 마지막 버전을 유지해주며 같은 key의 이전 버전을 삭제한다.
 
Log 압축은 Kafka를 DB 방식으로 사용하는 방법이라고 할 수 있다. 보유 기간을 영구로 설정하거나 topic의 log 압축을 활성화하면 데이터가 영구적으로 저장된다. 
 
Log 압축은 수천개의 클러스터 중 하나의 클러스터 상태를 봐야하는 경우에 유용하다. 클러스터가 응답하는 여부를 저장하는 대신 마지막 상태를 저장한다. 얼마나 많은 메시지가 queue에 있는지와 같은 최신 정보를 곧바로 이용할 수 있다.

- Monitoring

RabbitMQ는 웹 브라우저에서 RabbitMQ 서버를 다루거나 모니터하는 기능을 제공하여 친숙한 UI를 제공해준다. queue나 연결, 채널, exchange, 유저, 유저권한을 브라우저에서 다룰 수 있고 메시지 속도나 메시지의 전송 및 수신을 직접 처리할수도 있다.
 
Kafka의 경우 admin 기능이나 관리 기능들을 제공하는 오픈소스 툴이나 상용 툴이 있다.

- PUSH or PULL

RabbitMQ에서 메시지는 consumer에게 전송된다. consumer에 부하가 가는것을 방지 하기 위해서는(consumer가 메시지를 처리하는것보다 queue에 도착하는게 더 빠른 경우) prefetch 제한을 설정해야 한다. Consumer는 RabbitMQ로 부터 메시지를 당겨올수도 있는데 추천되는 방법은 아니다.
 
반면 Kafka의 경우 pull 모델을 사용하는데 consumer가 주어진 offset 에서 일괄 메시지를 요청한다.

- License

RabbitMQ는 Rabbit Tech. Ltd에서 만들어졌으며 해당 프로젝트는 2013년 Pivotal Software 사로 이관되었다. RabbitMQ의 소스코드는 Mozilla Public License를 따른다.
 
Kafka는 원래 LinkedIn 에서 만들어졌으며 2011년에 오픈소스화되어 Apache 재단에 이관되었다. Apache Kafka는 Apache 2.0 license를 따른다. Kafka와 같이 사용되는 component중 일부는 Confluent Community License 를 따르는데 Rest Proxy, Schema Registry, KSL이 있다. 이 License는 마음껏 다운로드하고 수정하고 재배포할 수 있지만 소프트웨어를 SaaS 제품으로 제공하는것은 허용하지 않는다.
 
두 license 모두 제약이 없는 오픈소스 소프트웨어 license이다. 만약 Kafka가 license를 변경할 경우 RabbitMQ와 같은 경우는 AMQP로 대체될 수 있지만 Kafka는 제약이 있다.

- Complexity

원 글을 작성한 필자의 의견으로는 RabbitMQ가 시작하기에 더 쉽다고 어필하고 잇다. Kafka는 topic/partition/message offset과 같은 추가적인 개념을 포함하고 있어서 더 복잡할 수 있다. Kafka를 사용할 경우 consumer 그룹과 offset을 어떻게 다루는지에 대해 더 친숙해져야 한다.

- The Kafka Ecosystem

Kafka는 단순한 broker가 아닌 streaming platform 이며 기본 배포한 외부에서 kafka와 쉽게 통합할 수 잇는 도구가 많다. kafka 생태계는 Kafka Core, Kafka Streams, Kafka Connect, Kafka REST Proxy, Schema Registry로 구성되어 있다. Kafka 생태계의 추가적인 툴들의 대부분은 Apache 산하가 아니라 Confluent 산하에 있다.
 
이런 툴들을 이용하면 코드를 작성하지 않고 거대한 시스템을 구성할 수 있는 이점이 있다.
 
Kafka Connect는 Kafka를 사용하는 다른 시스템과 통합하는 기능을 제공한다. 어떤 source 로 부터 데이터를 소비하는 data source를 추가하고 해당 데이터를 Kafka에 저장할 수 있으며 그 반대로 저장할 수도 있고 topic의 모든 데이터를 처리 또는 저장하기 위해 다른 시스템으로 보낼수도 있다. Kafka Connect를 사용해서 많은 것들을 할 수 있고 이미 이용할 수 있는 많은 connector들이 있기 때문에 무언가를 시작하기에 좋다.
 
Kafka REST Proxy를 이용하면 cluster 로 부터 메타 데이터를 수신할 수 있으며 간단한 REST API를 통해서 메시지를 소비하고 생산할 수 있다. 이 기능은 클러스터의 Control Panel 에서 쉽게 활성화할 수 있다.

- RabbitMQ use cases

일반적으로는 간단하고 전통적인 pub-sub 메시지 브로커를 원한다면 RabbitMQ를 선택하는게 왠만해선 좋다. 웬만한 scale이 아니면 Kafka를 써야지 처리가 가능할것 같다고 생각한 처리량도 RabbitMQ를 이용해서도 커버 가능한 경우가 많기 때문이다. 만약 요구사항이 channel이나 queue를 통한 시스템 통신을 다루는 정도로 간단하고, 데이터를 유지하거나 streaming 하는게 요구사항이 아니라면 RabbitMQ를 선택하는 편이 좋다.
 
신뢰성있는 background job을 실행해야하는 long-running task 와 application간 통신이나 통합(ex - 마이크로서비스간의 middleman)의 경우 다른 시스템이 작업을 시작할 수 있도록 단순 공지(ex - order 발행, order 상태 갱신, order 전송, 결제 등)하는 경우 RabbitMQ를 사용할 수 있다.

- Kafka use cases

일반적으로 저장하거나 처리 및 재처리 그리고 streaming 데이터를 분석하기를 원한다면 Apache kafka를 사용하는게 좋다. 감사를 받거나 메시지를 영구적으로 저장해야 할 필요가 있는 경우 또한 마찬가지다. 또한 데이터 분석(추적, 로깅, 보안) 이나 실시간 처리를 위한 2 가지 주요 사용 목적으로도 나누어 질 수 있다.
 
 

'Framework and Tool > MQ' 카테고리의 다른 글

Kafka - introduction  (0) 2022.06.06

댓글