Apache Pulsar vs. Kafka
분산 메시징 시스템은 현대 데이터 중심 아키텍처의 중추 역할을 한다.
기본 개념 및 역사
Apache Kafka
Apache Kafka는 2011년 LinkedIn에서 개발된 후 Apache 소프트웨어 재단으로 이관된 분산 스트리밍 플랫폼이다. 처음에는 LinkedIn 내부의 데이터 파이프라인 문제를 해결하기 위해 만들어졌지만, 이후 업계 표준 메시징 시스템으로 자리 잡았다. Kafka는 높은 처리량, 내구성, 확장성을 제공하는 로그 기반의 발행-구독(pub-sub) 메시징 시스템이다.
Apache Pulsar
Apache Pulsar는 2016년 Yahoo에서 개발되어 2018년에 Apache 소프트웨어 재단의 최상위 프로젝트가 되었다. Pulsar는 다중 테넌트, 고성능 서비스로 설계되었으며, Kafka와 같은 발행-구독 메시징 시스템의 특성과 전통적인 메시지 큐의 장점을 결합했다. Pulsar는 처음부터 클라우드 네이티브 환경을 염두에 두고 개발되었다.
아키텍처 및 데이터 관리
항목 | Apache Pulsar | Apache Kafka |
---|---|---|
아키텍처 | 계층적 설계 (Broker + BookKeeper) - 컴퓨팅/저장소 분리 | 단일 레이어 설계 - Broker가 데이터 저장 및 처리 담당 |
데이터 저장 | BookKeeper를 통한 세그먼트 기반 저장 (장기 보관 가능) | 로컬 디스크에 파티션 단위 저장 (보존 기간 설정 필요) |
확장성 | 저장소와 컴퓨팅을 독립적으로 확장 가능 (재조정 불필요) | 파티션 추가를 통한 수평 확장 (재조정 필요) |
복제 | 다중 데이터센터 간 지오 복제 지원 | 클러스터 내 복제 (지오 복제는 외부 도구 필요) |
아키텍처
Kafka는 상대적으로 단순한 아키텍처를 가지고 있다:
- 브로커(Broker): 메시지 저장 및 관리를 담당하는 서버
- 토픽(Topic): 메시지의 논리적 채널
- 파티션(Partition): 토픽은 여러 파티션으로 분할되어 병렬 처리
- ZooKeeper: 클러스터 메타데이터 관리 및 코디네이션(최신 버전에서는 KRaft로 대체 중)
- 프로듀서(Producer): 메시지를 토픽에 게시하는 클라이언트
- 컨슈머(Consumer): 토픽의 메시지를 구독하는 클라이언트
Kafka의 아키텍처에서는 스토리지와 컴퓨팅이 결합되어 있다. 각 브로커는 파티션을 저장하고 클라이언트 요청을 처리한다. 토픽의 각 파티션은 브로커에 할당되고, 파티션은 디스크에 저장된 순차적 로그로 구현된다.
Pulsar는 보다 복잡하지만 유연한 아키텍처를 가지고 있다:
- 브로커(Broker): 클라이언트 요청을 처리하고 메시지 전달을 조정
- 북키퍼(BookKeeper): 메시지 저장을 담당하는 분산 로그 저장소
- 북키(Bookie): BookKeeper의 개별 저장 노드
- 토픽(Topic): 메시지의 논리적 채널
- 파티션(Partition): Pulsar에서는 “샤드"라고도 함
- ZooKeeper: 클러스터 메타데이터 관리
- 프로듀서(Producer): 메시지를 토픽에 게시하는 클라이언트
- 컨슈머(Consumer): 토픽의 메시지를 구독하는 클라이언트
Pulsar의 가장 큰 아키텍처적 특징은 스토리지와 컴퓨팅의 분리이다. 브로커는 메시지 처리를 담당하지만, 실제 저장은 BookKeeper에서 이루어진다. 이로 인해 스토리지와 컴퓨팅을 독립적으로 확장할 수 있어 리소스 활용도가 향상된다.
메시징 모델
Kafka는 로그 중심 모델을 사용한다:
- 순차적 로그: 메시지는 추가만 가능한(append-only) 로그로 저장
- 오프셋 기반 소비: 컨슈머는 로그에서 특정 오프셋(위치)부터 메시지를 소비
- 파티션 기반 병렬 처리: 토픽은 여러 파티션으로 나뉘어 병렬 처리됨
- 컨슈머 그룹: 여러 컨슈머가 협력하여 토픽의 파티션을 소비
Kafka에서 메시지는 설정된 보존 기간 동안 유지되며, 같은 토픽에 대해 여러 컨슈머 그룹이 독립적으로 메시지를 처리할 수 있다.
Pulsar는 세그먼트 기반 모델을 사용하며, 두 가지 주요 메시징 패러다임을 지원한다:
- 발행-구독(Pub-Sub): Kafka와 유사한 다중 구독자 모델
- 큐(Queue): 단일 구독자가 메시지를 독점적으로 처리하는 모델
Pulsar의 주요 특징: - 세그먼트 기반 스토리지: 메시지는 세그먼트 단위로 저장되고 관리됨
- 다중 테넌시(Multi-tenancy): 네임스페이스와 테넌트 개념으로 리소스 분리
- 구독 유형: Exclusive, Shared, Failover, Key_Shared 등 다양한 구독 모드 지원
- 계층적 토픽 구조: 네임스페이스를 통한 논리적 토픽 그룹화
Pulsar의 메시징 모델은 전통적인 메시지 큐와 Kafka 스타일의 로그 기반 모델을 모두 지원하여 다양한 사용 사례에 적용 가능하다.
성능 및 처리
항목 | Apache Pulsar | Apache Kafka |
---|---|---|
처리량 | 초당 2.5배 높은 처리량 (벤치마크 기준) | 초당 수백만 메시지 처리 가능 |
지연 시간 | 일관된 단일 자릿수 밀리초(ms) 지연 시간 | 평균 10ms 이상 지연 (고부하 시 증가) |
메시지 소비 모델 | Push 기반 + 다중 소비 모드 (Exclusive/Shared/Failover) | Pull 기반 + Consumer Group 모델 |
데이터 재생 | 오프셋 없이 특정 시간/메시지 ID 기반 재생 가능 | 오프셋 기반 순차적 접근 |
성능 및 확장성
Kafka는 높은 처리량을 위해 최적화되어 있다:
- 순차적 I/O: 디스크 기반이지만 순차적 읽기/쓰기로 높은 성능 달성
- 제로 카피(Zero-Copy): 커널과 사용자 공간 간 불필요한 복사 방지
- 배치 처리: 프로듀서와 컨슈머에서 배치 처리로 성능 향상
- 파티션 기반 확장: 토픽의 파티션 수를 늘려 처리량 확장
Kafka의 확장은 브로커를 추가하고 파티션을 재분배하는 방식으로 이루어지며, 스토리지와 컴퓨팅이 함께 확장된다. 이는 특정 워크로드에서는 효율적이지만, 스토리지와 컴퓨팅 리소스 요구사항이 불균형할 때는 비효율적일 수 있다.
Pulsar는 낮은 지연 시간과 높은 처리량을 모두 달성하도록 설계되었다:
- 스토리지-컴퓨팅 분리: 브로커와 스토리지를 독립적으로 확장 가능
- 티어드 스토리지(Tiered Storage): 핫 데이터와 콜드 데이터를 다른 스토리지 계층에 배치
- 배치 인덱싱: 메시지 조회 성능 최적화
- 비동기 처리: 기본적으로 비동기 API를 제공하여 낮은 지연 시간 제공
Pulsar의 분리된 아키텍처 덕분에 처리량 요구사항과 스토리지 요구사항에 따라 각 계층을 독립적으로 확장할 수 있다. 또한 BookKeeper의 분산 특성 덕분에 스토리지가 자동으로 여러 북키에 분산되어 병목 현상을 줄인다.
기능 및 활용 사례
항목 | Apache Pulsar | Apache Kafka |
---|---|---|
멀티테넌시 | 네임스페이스 단위 리소스 격리 지원 | 기본적인 권한 관리만 제공 |
스트림 처리 | Pulsar Functions (경량 서버리스 기능) | Kafka Streams (풍부한 연산 연산자 지원) |
주요 사용 사례 | - 클라우드 네이티브 애플리케이션- 실시간 알림 시스템- 다중 테넌트 환경 | - 로그 집계- 실시간 분석- 이벤트 소싱 |
적합한 환경 | 동적 확장이 필요한 클라우드 환경 | 안정적인 고처리량 요구 환경 |
기능 비교
메시지 보존 및 티어드 스토리지
Kafka:- 토픽별 보존 정책 설정 가능(시간 또는 크기 기반)
- 기본적으로 단일 스토리지 계층 사용
- 외부 도구를 통한 콜드 스토리지 아카이빙 가능
Pulsar: - 내장된 티어드 스토리지 기능
- 핫 스토리지(BookKeeper)와 콜드 스토리지(S3, GCS 등) 자동 전환
- 무제한 메시지 보존이 경제적으로 가능
스키마 관리
Kafka:- Confluent Schema Registry(외부 도구)를 통한 스키마 관리
- 스키마 진화 지원
- 주로 Avro 형식 지원
Pulsar: - 내장된 스키마 레지스트리
- JSON, Avro, Protobuf 등 다양한 스키마 형식 지원
- 스키마 강제 및 진화 지원
트랜잭션 및 정확히 한 번 처리
Kafka:- Kafka Streams를 통한 정확히 한 번 처리 지원
- 트랜잭션 API 제공
Pulsar: - Pulsar 트랜잭션 API
- 정확히 한 번 처리 지원
- 멀티 토픽 트랜잭션 지원
스트림 처리
Kafka:- Kafka Streams: 강력한 내장 스트림 처리 라이브러리
- KSQL: SQL 기반 스트림 처리 언어
Pulsar: - Pulsar Functions: 서버리스 함수로 간단한 처리 지원
- Pulsar SQL: Presto 기반 SQL 쿼리 지원
- Pulsar IO: 외부 시스템과의 커넥터 제공
지역 간 복제
Kafka:- MirrorMaker(외부 도구)를 통한 지역 간 복제
- Mirror Maker 2.0에서 개선된 기능 제공
- 복잡한 설정 및 관리 필요
Pulsar: - 내장된 지역 간 복제 기능
- 토픽 단위의 세밀한 복제 정책 설정
- 관리가 상대적으로 용이
사용 사례
Kafka:
- 대규모 로그 집계 및 분석: 높은 처리량이 필요한 빅데이터 파이프라인
- 이벤트 소싱: 상태 변경을 이벤트로 저장하는 아키텍처
- 스트림 분석: Kafka Streams를 활용한 실시간 분석
- 단순한 발행-구독 시나리오: 복잡한 라우팅 없이 높은 처리량이 필요한 경우
- 기존 Kafka 생태계와 통합이 필요한 경우: 이미 구축된 Kafka 기반 시스템
Pulsar:
- 다중 테넌트 환경: 리소스 분리와 격리가 중요한 경우
- 하이브리드 메시징 패턴: 큐와 발행-구독을 모두 필요로 하는 시스템
- 지역 간 메시징: 전 세계적으로 분산된 메시징 인프라
- 장기 메시지 보존: 티어드 스토리지를 활용한 비용 효율적 보존
- 다양한 메시징 패턴: 다양한 구독 유형과 패턴이 필요한 복잡한 시스템
- 서버리스 함수 통합: Pulsar Functions를 활용한 간단한 처리 로직
운영 및 유지보수
항목 | Apache Pulsar | Apache Kafka |
---|---|---|
데이터 보존 | 계층적 저장소 (S3/GCS와 통합)로 무제한 보관 가능 | 로컬 디스크 용량에 의존 (오래된 데이터 삭제 필요) |
커뮤니티 | 성장 중인 생태계 (StreamNative, Yahoo 등 기업 지원) | 대규모 오픈소스 커뮤니티 (Confluent 엔터프라이즈 지원) |
코드 호환성 | Kafka-on-Pulsar (KoP)를 통해 Kafka 프로토콜 호환 | 네이티브 클라이언트 라이브러리 사용 필요 |
관리 복잡성
Kafka:
- 상대적으로 단순한 아키텍처로 운영이 쉬움
- 광범위한 도구 및 커뮤니티 지원
- ZooKeeper 의존성(최신 버전에서는 KRaft로 대체 중)
Pulsar:
- 복잡한 다계층 아키텍처로 운영이 복잡할 수 있음
- ZooKeeper와 BookKeeper 모두 관리 필요
- 관리 도구는 상대적으로 덜 성숙
모니터링 및 관리 도구
Kafka:
- 다양한 모니터링 도구(Confluent Control Center, Kafdrop, Kafka Tool 등)
- 풍부한 메트릭 및 JMX 통합
- 성숙한 운영 생태계
Pulsar:
- Pulsar Manager: 웹 기반 관리 도구
- Prometheus 및 Grafana 통합
- 상대적으로 덜 성숙한 도구 생태계
클라우드 네이티브 지원
Kafka:
- 후속 개발로 클라우드 지원 추가
- Confluent Cloud, Amazon MSK 등 관리형 서비스 존재
Pulsar:
- 처음부터 클라우드 네이티브로 설계
- 스토리지-컴퓨팅 분리로 클라우드 환경에 적합
- DataStax Astra Streaming 등 관리형 서비스 존재
장단점 요약
플랫폼 | 장점 | 단점 |
---|---|---|
Apache Pulsar | - 확장성 및 유연성 - 낮은 지연 시간 - 장기 데이터 보관 | - 상대적으로 새로운 기술 - Kafka 대비 적은 통합 도구 |
Apache Kafka | - 검증된 안정성 - 풍부한 생태계 - 고성능 스트림 처리 | - 지오 복제 복잡성 - 저장소 확장 제한 |
내구성 및 가용성
Kafka는 복제를 통해 내구성을 제공한다:
- 파티션 복제: 각 파티션은 설정된 복제 팩터에 따라 여러 브로커에 복제됨
- 리더-팔로워 모델: 각 파티션은 하나의 리더와 여러 팔로워를 가짐
- ISR(In-Sync Replicas): 동기화된 복제본의 개념으로 데이터 손실 방지
- 자동 장애 복구: 브로커 장애 시 리더 선출 및 자동 복구
Kafka의 내구성 모델은 강력하지만, 리더 선출과 복구 과정에서 일시적인 서비스 중단이 발생할 수 있다.
Pulsar는 BookKeeper를 통해 강화된 내구성 모델을 제공한다:
- 쿼럼 기반 복제: Write Quorum과 Ack Quorum을 통한 유연한 복제 정책
- 소규모 세그먼트: 메시지를 작은 세그먼트로 저장하여 효율적인 복제
- 북키 장애 자동 처리: 북키 장애 시 자동 복구 메커니즘
- 지역 간 복제: 내장된 지역 간 복제 기능으로 재해 복구 지원
Pulsar의 스토리지와 컴퓨팅 분리 덕분에 브로커 장애가 데이터 가용성에 미치는 영향이 최소화된다. 또한 BookKeeper의 쿼럼 기반 복제는 데이터 내구성을 강화한다.
성능 벤치마크 및 리소스 요구사항
벤치마크 결과는 테스트 환경 및 구성에 따라 크게 달라질 수 있지만, 일반적인 경향을 살펴보면:
- 처리량
- 대규모 배치 처리: Kafka가 종종 더 높은 최대 처리량 제공
- 다양한 워크로드: Pulsar가 다양한 메시지 크기와 패턴에서 일관된 성능 제공
- 지연 시간
- P99 지연 시간: Pulsar가 일반적으로 더 낮은 tail 지연 시간 제공
- 소규모 메시지: Pulsar의 비동기 프로세싱이 유리
- 대용량 메시지: 큰 차이 없음
- 리소스 사용
- 메모리 사용: Pulsar가 일반적으로 더 많은 메모리 요구
- 디스크 사용: Pulsar의 BookKeeper가 더 효율적인 스토리지 활용
- 네트워크 사용: Pulsar의 분리된 아키텍처로 더 많은 네트워크 트래픽 발생
Apache Pulsar vs. Kafka 비교
특성 | Apache Kafka | Apache Pulsar |
---|---|---|
개발 시작 | 2011년 LinkedIn | 2016년 Yahoo |
아키텍처 | 단일 계층(스토리지와 컴퓨팅 결합) | 다계층(스토리지와 컴퓨팅 분리) |
스토리지 엔진 | 브로커의 로컬 디스크(파티션 로그) | BookKeeper(분산 로그) |
메시징 패러다임 | 발행-구독 | 발행-구독 및 큐 |
토픽 구조 | 단일 수준 토픽 | 계층적 토픽(테넌트/네임스페이스/토픽) |
다중 테넌시 | 제한적 지원 | 내장 기능으로 강력 지원 |
파티셔닝 | 토픽 파티션 | 토픽 파티션(샤드) |
복제 모델 | 리더-팔로워 복제 | 쿼럼 기반 복제 |
구독 유형 | 컨슈머 그룹 | Exclusive, Shared, Failover, Key_Shared |
메시지 보존 | 시간/크기 기반 정책 | 티어드 스토리지 지원 |
스키마 관리 | 외부 Schema Registry | 내장 Schema Registry |
트랜잭션 | 토픽 내 트랜잭션 | 멀티 토픽 트랜잭션 |
스트림 처리 | Kafka Streams, KSQL | Pulsar Functions, Pulsar SQL |
지역 간 복제 | MirrorMaker(외부 도구) | 내장된 지역 간 복제 |
메시지 조회 | 오프셋 기반 | 메시지 ID 또는 시간 기반 |
오프셋 관리 | 클라이언트 또는 브로커에 저장 | 서버 측에서 관리 |
최대 처리량 | 매우 높음(최적화된 배치 처리) | 높음(다양한 워크로드에서 일관됨) |
지연 시간 | 낮음(밀리초 단위) | 매우 낮음(특히 tail 지연 시간) |
확장성 | 브로커 추가(스토리지와 컴퓨팅 함께) | 브로커/북키 독립적 확장 |
운영 복잡성 | 중간 | 높음(다계층 아키텍처) |
리소스 요구사항 | 중간 | 높음(특히 메모리) |
커뮤니티 성숙도 | 매우 높음 | 성장 중 |
생태계 | 광범위하고 성숙함 | 성장 중이지만 더 제한적 |
관리 도구 | 다양하고 풍부함 | 제한적이지만 개선 중 |
클라이언트 지원 | 다양한 언어(Java, Python, Go 등) | 다양한 언어(Java, Python, Go 등) |
관리형 서비스 | 다수(Confluent, AWS, GCP 등) | 일부(DataStax 등) |
적합한 워크로드 | 대용량 스트림 처리, 로그 집계 | 다중 테넌트, 하이브리드 메시징, 지역 간 배포 |
결론 및 선택 가이드
Kafka를 선택해야 하는 경우
- 단순하고 검증된 아키텍처를 선호하는 경우
- 매우 높은 처리량이 최우선 요구사항인 경우
- 성숙한 생태계와 광범위한 도구 지원이 필요한 경우
- 운영 팀이 Kafka 경험이 풍부한 경우
- Kafka Streams를 활용한 스트림 처리가 중요한 경우
Pulsar를 선택해야 하는 경우
- 스토리지와 컴퓨팅의 독립적 확장이 필요한 경우
- 다중 테넌트 환경을 구축하는 경우
- 다양한 메시징 패턴(큐, 발행-구독 등)이 필요한 경우
- 지역 간 메시징이 중요한 경우
- 장기 메시지 보존이 비용 효율적으로 필요한 경우
- 매우 낮은 tail 지연 시간이 중요한 경우
통합 접근 방식
일부 조직에서는 두 시스템을 함께 사용하는 통합 접근 방식을 채택하기도 한다:- Kafka: 기존 데이터 파이프라인 및 스트림 처리
- Pulsar: 다중 테넌트 요구사항, 지역 간 메시징, 장기 보존
이러한 접근 방식은 각 시스템의 강점을 최대한 활용할 수 있지만, 운영 복잡성과 비용이 증가할 수 있다.
용어 정리
용어 | 설명 |
---|---|
파티션(Partition) | Kafka에서 **파티션(Partition)**은 데이터를 효율적으로 저장하고 처리하기 위해 **토픽(Topic)**을 나누는 기본 단위이다. 파티션은 Kafka의 병렬 처리, 확장성, 고가용성을 가능하게 하는 핵심 요소로, 분산 시스템에서 메시지를 관리하고 처리하는 데 중요한 역할을 한다. 파티션의 역할 1. 병렬 처리: - 여러 컨슈머(Consumer)가 서로 다른 파티션에서 데이터를 동시에 읽을 수 있어 처리 속도가 향상된다. - 예: Consumer A는 Partition 1, Consumer B는 Partition 2에서 데이터를 읽음. 2. 확장성: - 토픽에 더 많은 파티션을 추가함으로써 시스템의 처리량을 확장할 수 있다. - 각 파티션은 클러스터 내의 서로 다른 브로커(Broker)에 분산되어 저장된다. 3. 순서 보장: - 각 파티션 내에서는 메시지의 순서가 보장되므로, 순차적인 데이터 처리가 필요한 경우 유용하다. - 예: 시계열 데이터, 트랜잭션 로그 등. 4. 고가용성: - 파티션은 복제(replication)를 통해 클러스터 내 여러 브로커에 저장되므로, 장애 발생 시에도 데이터 손실 없이 서비스가 지속된다. |