메시지 브로커 중에 Kafka를 도입한 이유

2025. 3. 6. 20:51Project/Monicar

메시지 브로커란?

메시지 브로커는 애플리케이션 간 서로 통신할 때 정보를 주고받을 수 있도록 도와주는 소프트웨어이다.

우체국처럼 메시지를 보내는 쪽인 **생산자(Producer)**와 메시지를 받는 쪽인 소비자(Comsumer) 사이에서 메시지를 전달하는 역할을 수행한다.

그렇기 때문에 MSA(Micro Service Architecture) 또는 분산 시스템에서 서비스 간 통신에 주로 사용되는 경우가 많고, 시스템 로그 처리, 비동기 메시지 큐 등 다양한 곳에서 활용된다.

왜 메시지 브로커가 필요한가?

메시지 브로커가 필요한 이유는 다음과 같다.

편지를 받는 사람(Consumer)는 편지를 쓰는 사람(Producer)이 편지를 다 쓸때까지(=메시지를 생산할때까지), 멍 때리며 가만히 있지 않는다. 무언가 일을 하고 있다가 편지를 받으면 비로소 편지를 읽기 시작한다.

서비스도 마찬가지이다.

한 서비스(Consumer)가 다른 서비스(Producer)로부터 메시지를 받기 전까지 자신의 일을 하다가 메시지를 받으면 그 메시지를 처리할 것이다. (=비동기적)

메시지 브로커는 우체국과 같은 역할을 한다.

한 서비스(Producer)가 메시지를 생산해서 메시지 브로커에게 전달하면 규칙에 따라 다른 서비스(Consumer)에게 메시지를 전달한다.

이렇게 되면 메시지 브로커를 이용하면 각 서비스들은 직접적으로 메시지를 교환하지 않는다.

그렇기 때문에 각 서비스들의 결합도가 낮아지게 된다. 결과적으로 각 서비스들은 독립적으로 개발과 운영이 쉬워지게 된다. 이런 확실한 이점때문에 MSA에서 활용되는 경우를 많이 볼 수 있다.

이외에도 메시지 처리량이 늘면 메시지 브로커를 확장하기 용이하고, 메시지 전달이 실패해도 재전송을 통해 데이터 손실을 방지할 수 있다.


Kafka VS RabbitMQ

Message Retention

  • kafka는 메시지 보존 정책에 따라 메시지가 유지된다.
  • 즉, 모든 메시지는 설정된 특정 기간동안 디스크에 저장된다.
  • 만약 데이터를 주간 단위로 저장해야한다면, 메시지 보존 기간을 7일로 설정할 수 있다.
  • 위 사진처럼 Consumer가 M1, M2, M3를 처리하면 메시지는 디스크에 설정된 기간동안 남아있게 되기 때문에 다른 Consumer(심지어 같은 Consumer)도 M1, M2, M3를 소비할 수 있다.

 

RabbitMQ

  • RabbitMQ는 Consumer가 성공적으로 처리했음을 확인할때까지 메모리나 디스크에 메시지를 저장한다.
  • 즉, Consumer가 메시지를 한번 소비하면 사라진다.
  • 따라서 같은 메시지를 처리하려면 Producer가 다시 메시지를 발행해야한다.

Message Routing

Kafka

  • Kafka는 메시지에 대한 라우팅 메커니즘이 없다.
  • Producer가 어떤 Topic(또는 Partition)에 쓸지 알려주고 Kafka는 그 특정 topic에 메시지를 발행한다.

Topic - 메시지가 분류되어 발행되는 카테고리로, 소비자(Consumer)가 구독할 수 있는 논리적인 채널

Partition - 토픽 내에서 메시지를 세분화하여 저장하는 물리적 단위, 메시지의 순서와 분산처리를 가능하게 한다.

RabbitMQ

  • RabbitMQ는 Exchange를 사용하여 하나 이상의 큐로 메시지를 라우팅하는 라우팅 메커니즘을 가지고 있다.

Multiple Consumers

Kafka

  • Kafka는 파티셔닝을 이용하여 여러 Consumer에게 메시지를 발행한다.
  • 그림을 보면, 한 Topic은 여러 Partition을 가질 수 있으며, 각 Partition은 Consumer Group당 오직 하나의 Consumer를 가질 수 있다.따라서 Kafka에서는 메시지 순서가 보장된다.

RabbitMQ

  • RabbitMQ는 하나의 Queue에 여러 Consumer가 있을 수 있다.
  • 이는 Producer가 빠르고 Consumer가 느린 경우 유용할 수 있다.
  • 하지만 여러 Consumer가 있기 때문에 경쟁 소비자 패턴이 발생하여 큐의 메시지가 순서대로 처리되지 않을 수 있다.

그래서 둘중에 무엇을 써야할까? (3~5는 멘토님의 의견입니다.)

시스템의 성격에 따라 적합한 메시징 시스템이 다르다.

빠르고 대규모 데이터 스트리밍 처리가 필요한 회사들은 Kafka를 핵심 메시징 시스템으로 선호하는 반면,

거래량이 적고 대규모 데이터 스트리밍 처리를 필요로 하지 않는 회사들은 RabbitMQ를 선호한다.

현재 모니카 서비스는 적어도 15000대 이상의 차량이 시동 on, 1분당 60개의 gps데이터, 시동 off를 요청하고 있다.

  1. 특히, gps데이터는 15000 * 60 = 약 90만개의 데이터를 1분당 요청한다.

이는 대규모 데이터이기때문에 Kafka의 도입이 마땅하다고 여겼다.

  1. RabbitMQ는 Consumer가 성공적으로 처리했음을 확인할때까지 메모리나 디스크에 메시지를 저장한다. 즉, Consumer가 메시지를 한번 소비하면 사라진다. 따라서 같은 메시지를 처리하려면 Producer가 다시 메시지를 발행해야한다.

→ 현재, 시동 on, gps데이터, 시동 off를 요청하며, 차량을 관제하고 있다. 관제 측면에서 이는 중요한 데이터라고 판단했기 때문에 데이터의 유실측면에서 좋지 못하다고 판단했다.

  1. 차량이 개별적으로 시간순으로 적재되어야 하는 부분에서 차량 번호를 키로 사용하여 시동 ON, 주행데이터, 시동 OFF가 순차적으로 각 파티션에 적재될 수 있다.

파티션 별로 병렬 적재가 가능해져 RabbitMQ의 순서 기반 단일 처리 대비 빠른 처리가 가능하다.

  1. 차량이 기하급수적으로 증가하는 상황 (중국 전기차 업체 BYD의 등장과 롯데렌터카 SK렌터카의 홍콩 사모펀드 인수) 등의 시장으로 인프라 확장이 불가피할 때, RabbitMQ의 경우 스케일아웃이 수월하지 않아 도중 중단이 발생할 수 있다.

→ 카프카는 스토리지 크기를 유연하게 증가시킬 수 있는 방식

  1. 이전 메시지도 다시 재생할 수 있다. 사실 차량 데이터 중, 과거 기록중에 이슈가 있다던가 하더라도 메시지의 수신 오류인지 도메인 로직 오류인지 확실하게 인지하지 못할 때가 많다.
  2. 차량 데이터가 안정적인 통신 방식으로 수집되지 않을 수 있는 무선 환경이다 보니, 이전 기록을 롤백해서 다시 재처리할 수 있는 방안이 고려될 수 있어야 한다.

→ ACK 기준을 특정 시점 키로 당겨서 메시지 적재를 재처리할 수도 있어 로직의 이슈인지, 차량 통신 불량인지도 파악이 가능.

참고로, 현재 모니카 서비스는 ACK를 1로 설정하였다.

ack는 간단하게 말해 확인의 의미이다. 프로듀서가 메시지를 보내고, 브로커에게 잘 전달되었는지 확인하기 위한 옵션으로 [1, 0, -1(all)]값으로 설정할 수 있다.

ack = 0

  • 프로듀서가 메시지를 보내고 브로커에게 메시지 전달이 정상적으로 되었는지를 확인하지 않는다. 메시지를 보내기만 하기 때문에 성능면에서 세가지 옵션 중 가장 월등하지만, 메시지 전달이 정상적으로 되고 있는지를 보장하지 않는다. 메시지 유실보다 메시지 처리량이 더 중요하게 생각될때 적용할 수있다.

ack = 1

  • 프로듀서가 메시지를 보내고, 리더에게 메시지가 잘 전달되었는지를 확인한다. 리더는 메시지를 받아 로그파일에 이를 추가하고, 다른 팔로워들이 메시지를 복제하는 것을 기다리지 않고 잘 전달되었다고 프로듀서에게 알린다. 이 옵션은 리더가 메시지를 받은 것을 보장하지만, 복제가 되었는지를 확인하지 않기 때문에 리더가 메시지를 받고 장애가 발생할 경우 메시지가 유실될 수 있다. 세 옵션 중, 지연시간, 처리량, 안정성 면에서 가장 중도의 길을 걷는 옵션이다.

ack = all (-1)

  • 프로듀서가 메시지를 보내고, 리더와 ISR팔로워들이 메시지를 모두 전달받았는지를 확인한다. 리더는 모든 ISR들이 메시지를 복제했음을 확인한 뒤, 프로듀서에게 메시지의 전달이 잘 이루어졌다고 알린다. 이 옵션을 적용하면, 메시지의 전달에 있어, 상대적으로 매우 긴 시간이 필요하지만, 다른 옵션들에 비해 월등한 안정성을 제공한다.