Kafka vs RabbitMQ vs Redis (Pub/Sub) 비교 및 작동 방식 분석
Kafka, RabbitMQ, Redis는 메시지 큐(Message Queue, MQ) 또는 Pub/Sub(발행-구독) 시스템을 제공하는 대표적인 기술이다.
각 기술의 작동 방식, 사용하는 알고리즘, 장단점을 비교하여 어떤 상황에서 적절한지 분석하고 앞으로 사용할 프로젝트에서 어떻게 적용할지 고려해보려고 한다.
1. Kafka (Apache Kafka)
Kafka는 분산 로그 기반의 메시지 스트리밍 플랫폼이다.
대규모 데이터를 실시간으로 수집, 저장 및 처리하는 데 최적화되어 있으며, 높은 처리량과 내구성을 제공한다.
Kafka 작동 방식
• Publish-Subscribe 모델(Pub/Sub) 기반.
• Producer(생산자)가 메시지를 Topic(토픽)에 보냄.
• Broker(브로커)가 메시지를 저장하고, 여러 개의 Partition(파티션)으로 분산하여 저장.
• Consumer(소비자)가 Topic에서 메시지를 읽음 (Pull 방식).
• 메시지는 일정 기간 동안 저장되며, Consumer가 여러 번 읽을 수 있음.
Kafka에서 Producer가 메시지를 보내고 Consumer가 찾는 과정
1. Producer가 특정 Topic으로 메시지를 전송
• Producer는 Kafka Broker에 특정 Topic을 지정하여 메시지를 보낸다.
• 메시지는 Topic 내의 여러 Partition 중 하나에 저장된다.
2. Broker는 메시지를 저장하고 Partition에 할당
• 메시지는 Topic 내부의 Partition 중 하나로 라우팅된다.
• Partition은 여러 개로 나뉘며, 메시지는 특정 Partition에 저장된다.
3. Consumer는 해당 Topic을 구독하여 메시지를 가져감
• Consumer는 Kafka Broker에 Pull 요청을 보내서 메시지를 가져온다.
• Consumer는 Partition의 Offset 정보를 기반으로 메시지를 찾는다.
Producer가 메세지를 특정 Partition으로 보내는 알고리즘
Kafka의 Producer는 메시지를 특정 Partition으로 할당하는 방식을 결정하는 여러 가지 전략을 제공한다.
1) Key 기반 Partitioning (Hash 알고리즘)
Producer가 메시지를 보낼 때, 특정 Key 값을 설정하면 Kafka가 Key를 해싱하여 특정 Partition으로 메시지를 라우팅한다.
동작 방식
• Producer가 메시지를 보낼 때 Key를 포함하면 Kafka가 Key를 해싱하여 특정 Partition을 선택한다.
• 같은 Key를 가진 메시지는 항상 같은 Partition에 저장된다.
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "user123", "message-content");
producer.send(record);
• Key "user123"을 해싱하여 특정 Partition으로 전송됨.
• 동일한 Key "user123"를 가진 메시지는 항상 동일한 Partition에 저장된다.
사용 알고리즘
• Kafka는 기본적으로 MurMur2 해시 함수를 사용하여 Partition을 결정한다.
• 해시값을 Partition 개수로 나눈 나머지를 이용하여 Partition을 선택한다.
partition = hash(key) % num_partitions
Round-Robin 방식
Key를 지정하지 않으면 Kafka는 메시지를 Round-Robin 방식으로 균등하게 Partition에 분배한다.
동작 방식
• 메시지가 들어올 때마다 순차적으로 다음 Partition에 저장됨.
• 특정 Partition에 메시지가 집중되지 않고, 균등한 부하 분산 효과를 가짐.
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", null, "message-content");
producer.send(record);
Custom Partitioning
Kafka는 사용자가 직접 Partition을 선택하는 로직을 정의할 수 있는 Custom Partitioning 기능을 제공한다.
public class CustomPartitioner implements Partitioner {
@Override
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
return key.hashCode() % cluster.partitionCountForTopic(topic);
}
}
Kafka의 주요 알고리즘
• Partitioning Algorithm: 메시지를 파티션 단위로 저장하여 병렬 처리 가능.
• Replication Algorithm: Leader-Follower 모델을 사용하여 데이터 손실 방지.
• Log-based Storage: 메시지를 로그 형태로 저장하고, Consumer가 오프셋을 지정하여 읽을 수 있음.
Kafka의 장점
• 고성능 및 확장성이 뛰어나다.
• 데이터 영속성 및 내구성이 보장되며, 메시지가 브로커에 저장되어 재처리 가능하다.
• Consumer가 여러 번 메시지를 읽을 수 있어 데이터를 손실 없이 활용할 수 있다.
• 분산 아키텍처를 지원하여 클러스터로 확장 가능하다.
Kafka의 단점
• 설치 및 운영이 복잡하다. Zookeeper, Broker 설정이 필요하다.
• 즉시성보다는 데이터 스트리밍에 적합하며, 빠른 응답이 필요한 요청-응답 패턴에는 부적절하다.
• 메시지 순서를 완벽히 보장하지 않는다. 같은 Topic 내의 Partition에서는 순서를 유지하지만, 전체적인 순서는 보장되지 않는다.
2. RabbitMQ
RabbitMQ는 AMQP(Advanced Message Queuing Protocol) 기반의 메시지 브로커이다.
클래식 메시지 큐 구조를 따르며, 빠른 메시지 전송과 메시지 보장이 필요할 때 적합하다.
RabbitMQ 작동 방식
• Producer(생산자)가 메시지를 Exchange(교환기)로 보냄.
• Exchange가 메시지를 Queue(큐)에 전달 (Routing Rule 적용 가능).
• Consumer(소비자)가 Queue에서 메시지를 읽음 (Push 방식).
• Acknowledgment(ACK) 지원으로 메시지가 처리되었는지 확인 가능.
RabbitMQ의 주요 알고리즘
• Fanout, Direct, Topic, Header Exchange를 사용하여 메시지를 다양한 방식으로 큐에 라우팅.
• Message Acknowledgment Algorithm을 사용하여 메시지 손실 방지를 위해 ACK 메커니즘을 지원.
• Priority Queue Algorithm을 사용하여 우선순위가 높은 메시지를 먼저 처리.
RabbitMQ의 장점
• 낮은 지연 시간을 제공하여 메시지를 빠르게 전송할 수 있다.
• 메시지 전달 보장이 가능하며, ACK 기능을 통해 메시지 손실을 방지할 수 있다.
• 다양한 메시지 라우팅 방식을 지원하여 특정 Consumer에게만 메시지를 전송할 수 있다.
• 트랜잭션을 지원하여 메시지의 원자적(Atomic) 처리가 가능하다.
RabbitMQ의 단점
• 대량의 메시지를 처리하는 데 적합하지 않다. Kafka에 비해 고성능 데이터 스트리밍에는 불리하다.
• 메시지 저장이 비효율적이며, 디스크에 저장하면 성능이 저하될 수 있다.
• 운영 부담이 있으며, 복잡한 Exchange 설정이 필요할 수 있다.
3. Redis (Pub/Sub)
Redis는 인메모리 데이터베이스이며, Pub/Sub 기능을 제공하는 메시지 브로커 역할도 수행 가능하다.
RabbitMQ, Kafka와 달리 메시지를 영속적으로 저장하지 않으며, 빠른 실시간 메시징에 적합하다.
Redis Pub/Sub 작동 방식
• Publisher(발행자)가 특정 Channel(채널)에 메시지를 발행.
• Subscriber(구독자)가 특정 Channel을 구독하여 메시지를 수신.
• 메시지는 휘발성(Volatile)이며, 소비자가 구독하지 않으면 손실됨.
Redis의 주요 알고리즘
• Pub/Sub Algorithm을 사용하여 메시지를 특정 채널에 전달하고, 구독한 모든 Consumer에게 전송.
• LRU(Least Recently Used) Caching Algorithm을 사용하여 메모리 관리 시 자주 사용되지 않는 데이터를 삭제.
• Replication Algorithm을 사용하여 여러 개의 Redis 인스턴스에 데이터를 복제 가능.
Redis의 장점
• 매우 빠른 성능을 제공하며, 메시지를 메모리에서 직접 처리하므로 낮은 지연 시간(Latency)을 보장한다.
• 설정이 간단하여 Kafka, RabbitMQ보다 설치 및 설정이 쉽다.
• 간단한 Pub/Sub 모델을 제공하여 즉각적인 메시지 전송이 필요할 때 적합하다.
Redis의 단점
• 메시지가 영속적으로 저장되지 않으며, Consumer가 연결되지 않으면 메시지 손실이 발생할 수 있다.
• 확장성이 제한적이며, Kafka처럼 분산 시스템을 통한 대량 데이터 처리는 어렵다.
• 메시지 큐의 기능이 부족하며, 메시지 우선순위, ACK 지원이 없다.
단점을 보완할 수 있는 방법
Redis의 Pub/Sub에서 메시지는 큐로 저장되지 않는다.
메시지는 발행(Publish)될 때 구독(Subscribe) 중인 클라이언트에게만 실시간으로 전송되며, 이후에는 저장되지 않는다.
Redis Pub/Sub의 메시지 처리 방식
1. Publisher(발행자)가 특정 채널(Channel)에 메시지를 발행(Publish).
2. Subscriber(구독자)가 해당 채널을 구독하고 있으면 메시지를 즉시 수신.
3. 구독자가 연결되지 않은 상태에서 메시지가 발행되면 메시지는 손실됨.
4. 메시지는 브로커(Redis 서버) 내에 저장되지 않고 즉시 전달되기 때문에, 구독하지 않은 상태에서는 수신할 수 없음.
Redis에서 메시지를 저장하려면?
Redis 자체적으로 Pub/Sub의 메시지를 큐에 저장하지 않지만, Redis의 Stream 또는 List 데이터 구조를 활용하여 메시지 큐처럼 사용할 수 있다.
1) Redis Stream을 사용한 메시지 저장
Redis 5.0 이상에서는 Redis Streams를 이용하여 메시지를 저장하고 Consumer가 가져갈 수 있도록 관리할 수 있다.
# 메시지 추가 (XADD 사용)
XADD mystream * message "Hello, Redis Stream!"
• XADD 명령어를 사용하여 메시지를 저장할 수 있으며, Consumer가 필요할 때 가져갈 수 있음.
• Kafka처럼 데이터를 일정 기간 동안 저장하며, 여러 Consumer가 처리할 수 있는 구조를 가짐.
2) Redis List를 사용한 메시지 큐
LPUSH와 BRPOP을 활용하여 간단한 큐 기능을 구현할 수도 있다.
# Producer가 메시지 전송 (Queue에 저장)
LPUSH myqueue "Task 1"
# Consumer가 메시지 가져오기
BRPOP myqueue 0
• LPUSH는 리스트의 앞에 데이터를 추가하여 큐처럼 사용 가능.
• BRPOP은 블로킹 방식으로 데이터를 꺼내오기 때문에 메시지가 대기열에 유지됨.
Redis의 기본적인 Pub/Sub은 메시지를 저장하지 않으며, 메시지가 즉시 전송되고 이후에는 사라진다.
하지만 Redis Streams 또는 List를 활용하면 메시지를 큐에 저장하여 필요할 때 가져올 수 있는 방식으로 변경 가능하다.
메시지의 저장 및 보장이 필요하다면 Kafka나 RabbitMQ 같은 메시지 큐 솔루션을 사용하는 것이 더 적절하다.
4. Kafka vs RabbitMQ vs Redis 비교 요약
비교 항목 | Kafka | RabbitMQ | Redis (Pub/Sub) |
작동 방식 | 로그 기반 메시지 큐 (Pub/Sub) | 전통적인 메시지 큐 | Pub/Sub 모델 |
메시지 저장 | 가능 (디스크 저장) | 가능 (디스크 저장 가능) | 없음 (메모리 기반) |
메시지 순서 보장 | 부분적 (Partition 단위) | 가능 (FIFO 지원) | 불가능 |
메시지 전달 방식 | Pull 방식 (Spring kafka는 Eventlistenr방식 지원) | Push 방식 | Push 방식 |
확장성 | 매우 높음 (클러스터 지원) | 높음 (클러스터 지원) | 낮음 (단일 인스턴스 기반) |
지연 시간 (Latency) | 높음 (밀리초 ~ 초 단위) | 낮음 (밀리초 단위) | 매우 낮음 (마이크로초 단위) |
트랜잭션 지원 | 지원 (Exactly Once 가능) | 지원 (ACK 기반) | 지원 안함 |
처리량 (Throughput) | 매우 높음 (수백만 TPS) | 높음 (수십만 TPS) | 높음 (메모리 기반) |
운영 난이도 | 높음 (클러스터 운영 필요) | 중간 (Exchange 설정 필요) | 낮음 (설정 간단) |
2. Redis Pub/Sub과 메시지 큐(RabbitMQ, Kafka) 비교
Redis Pub/Sub은 메시지를 단순한 브로드캐스트 방식으로 전송하며, 메시지 보관 기능이 없다.
반면, RabbitMQ나 Kafka 같은 메시지 큐 시스템은 메시지를 저장하고 소비자(Consumer)가 필요할 때 가져가도록 설계되어 있다.
특징Redis Pub/SubRabbitMQKafka
메시지 저장 여부 | 저장되지 않음 | 큐에 저장 가능 | 로그 기반으로 저장 |
메시지 보장 | 보장되지 않음 (구독자가 없으면 손실) | ACK 처리로 보장 가능 | 재처리 가능 |
메시지 소비 방식 | Push 기반 (즉시 전달) | Push 기반 (Queue에서 하나씩 전달) | Pull 기반 (Consumer가 직접 가져감) |
5. 결론: 언제 어떤 MQ를 선택해야 할까?
Kafka를 선택해야 하는 경우
• 대용량 데이터 스트리밍이 필요한 경우 (로그 수집, 실시간 이벤트 처리).
• 메시지를 오래 저장하고 여러 번 처리해야 하는 경우.
• 고성능이 필요한 대규모 분산 시스템.
RabbitMQ를 선택해야 하는 경우
• 빠른 메시지 전달이 중요한 경우 (채팅 서비스, 주문 처리).
• 메시지 손실을 방지하고 트랜잭션이 필요한 경우.
• 다양한 라우팅 방식이 필요한 경우.
Redis Pub/Sub을 선택해야 하는 경우
• 낮은 지연 시간이 중요한 경우 (실시간 알림, 캐시).
• 설정이 간단하고 빠른 메시지 처리가 필요한 경우.
• 메시지 저장이 필요 없는 경우.
Kafka는 데이터 스트리밍, RabbitMQ는 메시지 큐, Redis는 빠른 Pub/Sub에 강점을 가진다.
사용 목적에 맞춰 적절한 메시지 브로커를 선택하는 것이 중요하다.