Redpanda 완벽 가이드 — JVM 없는 Kafka API 호환 C++ 스트리밍 플랫폼

Redpanda 완벽 가이드 — JVM 없는 Kafka API 호환 C++ 스트리밍 플랫폼

이 글의 핵심

Redpanda는 Apache Kafka 프로토콜을 100% 호환하면서 JVM·ZooKeeper·KRaft 복잡성을 제거하고 C++ + Seastar 프레임워크로 재구현한 스트리밍 플랫폼입니다. 단일 바이너리, thread-per-core 아키텍처, 낮은 테일 지연(p99)으로 프로덕션 운영을 극적으로 단순화합니다. 이 글은 설치·운영·Kafka 대비 차이·Tiered Storage·Kubernetes 배포까지 정리합니다.

Redpanda가 해결하는 문제

Kafka는 10년 이상 이벤트 스트리밍의 표준이지만 운영 부담이 만만치 않습니다.

Kafka 고통점Redpanda 해법
ZooKeeper → KRaft 마이그레이션 복잡성단일 바이너리, Raft 내장
JVM GC pause로 p99 튐C++ + Seastar, GC 없음
브로커당 수백 토픽·파티션에서 성능 저하thread-per-core, 효율적
복잡한 운영 도구(Kafka Manager 등) 필요내장 rpk CLI + 콘솔
스키마 레지스트리·Connect 별도 배포기본 포함

Redpanda는 “Kafka API는 그대로 유지, 내부는 완전 재설계” 라는 접근입니다. 따라서 기존 클라이언트·도구 투자를 유지하면서 운영을 단순화합니다.

아키텍처

┌──────────────────────────────────────────┐
│ Redpanda Broker (단일 바이너리)          │
│                                            │
│   ┌─────────────┐  ┌─────────────┐       │
│   │  core 0     │  │  core 1     │       │
│   │  (shard 0)  │  │  (shard 1)  │       │
│   │  파티션 리더│  │  파티션 리더│  ...  │
│   └─────────────┘  └─────────────┘       │
│                                            │
│   Raft 복제  ◄──►  다른 브로커            │
│   Kafka API / Admin API / Schema Registry │
│   / Pandaproxy (HTTP)                     │
└──────────────────────────────────────────┘

핵심 설계:

  • Thread-per-core: 각 코어가 shard → lock free
  • Raft 합의: 메타데이터·로그 복제 모두 Raft (ZK 없음)
  • io_uring: 비동기 I/O로 컨텍스트 스위칭 최소화
  • Tiered Storage: 오래된 세그먼트를 S3/GCS로 자동 오프로드

설치

Docker (1노드 개발)

docker run -d --name redpanda \
  -p 9092:9092 -p 9644:9644 -p 8081:8081 -p 8082:8082 \
  docker.redpanda.com/redpandadata/redpanda:latest \
  redpanda start \
    --overprovisioned \
    --smp 1 --memory 1G --reserve-memory 0M \
    --node-id 0 --check=false \
    --kafka-addr PLAINTEXT://0.0.0.0:9092 \
    --advertise-kafka-addr PLAINTEXT://localhost:9092

# rpk CLI
docker exec -it redpanda rpk cluster info

Kubernetes (Helm)

helm repo add redpanda https://charts.redpanda.com
helm install redpanda redpanda/redpanda \
  --version 5.9.0 \
  --namespace redpanda --create-namespace \
  --set statefulset.replicas=3 \
  --set resources.cpu.cores=4 \
  --set resources.memory.container.max=8Gi \
  --set storage.persistentVolume.size=200Gi

Console UI도 함께:

helm install redpanda-console redpanda/console \
  --namespace redpanda \
  --set console.config.kafka.brokers='{redpanda-0.redpanda.redpanda.svc.cluster.local:9093}'

브라우저에서 토픽·메시지·컨슈머 그룹을 시각화해 관리합니다.

rpk: 통합 CLI

# 클러스터 상태
rpk cluster info
rpk cluster health

# 토픽
rpk topic create orders --partitions 6 --replicas 3
rpk topic list
rpk topic describe orders

# 메시지 produce/consume
rpk topic produce orders
> {"id": 1, "amount": 100}

rpk topic consume orders --num 10

# 컨슈머 그룹
rpk group list
rpk group describe my-group

# ACL
rpk acl create --allow-principal User:alice --operation read --topic orders

# 스키마 레지스트리
rpk registry schema create orders-value --schema schema.avsc --type avro

Kafka의 kafka-topics.sh·kafka-console-producer.sh·여러 개 나뉜 도구가 한 CLI로 통합됩니다.

클라이언트: Kafka 코드 그대로

Node.js (KafkaJS)

import { Kafka } from "kafkajs"

const kafka = new Kafka({
  clientId: "my-app",
  brokers: ["redpanda:9092"],
})

const producer = kafka.producer()
await producer.connect()
await producer.send({
  topic: "orders",
  messages: [{ key: "user-42", value: JSON.stringify({ amount: 100 }) }],
})

const consumer = kafka.consumer({ groupId: "order-processor" })
await consumer.connect()
await consumer.subscribe({ topic: "orders", fromBeginning: true })
await consumer.run({
  eachMessage: async ({ message }) => {
    console.log(message.value?.toString())
  },
})

Python (confluent-kafka)

from confluent_kafka import Producer, Consumer

p = Producer({"bootstrap.servers": "redpanda:9092"})
p.produce("orders", key="user-42", value='{"amount": 100}')
p.flush()

c = Consumer({
    "bootstrap.servers": "redpanda:9092",
    "group.id": "order-processor",
    "auto.offset.reset": "earliest",
})
c.subscribe(["orders"])
while True:
    msg = c.poll(1.0)
    if msg: print(msg.value())

Go (franz-go)

cl, _ := kgo.NewClient(
    kgo.SeedBrokers("redpanda:9092"),
    kgo.ConsumerGroup("order-processor"),
    kgo.ConsumeTopics("orders"),
)
defer cl.Close()

fetches := cl.PollFetches(ctx)
fetches.EachRecord(func(r *kgo.Record) {
    fmt.Printf("%s\n", r.Value)
})

주소만 Redpanda로 바꾸면 끝입니다.

스키마 레지스트리

# 스키마 등록
curl -X POST http://redpanda:8081/subjects/orders-value/versions \
  -H "Content-Type: application/json" \
  -d '{"schema": "{\"type\":\"record\",\"name\":\"Order\",\"fields\":[{\"name\":\"id\",\"type\":\"long\"},{\"name\":\"amount\",\"type\":\"double\"}]}"}'

# 호환성 체크
curl http://redpanda:8081/compatibility/subjects/orders-value/versions/latest \
  -H "Content-Type: application/json" \
  -d '{"schema": "..."}'

Confluent Schema Registry와 동일한 REST API로 기존 도구가 그대로 동작합니다.

Redpanda Connect (구 Benthos)

Kafka Connect 대안으로 YAML 기반의 선언적 스트림 프로세싱 + 커넥터:

# connect.yaml
input:
  kafka_franz:
    seed_brokers: ["redpanda:9092"]
    topics: ["orders"]
    consumer_group: "order-enricher"

pipeline:
  processors:
    - bloblang: |
        root = this
        root.enriched_at = now()
        root.region = metadata("kafka_key").string()

output:
  kafka_franz:
    seed_brokers: ["redpanda:9092"]
    topic: "orders.enriched"
redpanda-connect run connect.yaml

수백 가지 입력·출력 커넥터(S3, Postgres CDC, HTTP, Elasticsearch, Snowflake, Pulsar, NATS 등)를 단일 바이너리로 제공해 Kafka Connect 클러스터를 별도 운영할 필요가 없습니다.

Tiered Storage: S3 오프로드

로그 보존을 길게 가져가면서 로컬 SSD 비용을 줄이는 핵심 기능:

# redpanda.yaml
redpanda:
  cloud_storage_enabled: true
  cloud_storage_bucket: "my-redpanda-archive"
  cloud_storage_region: "ap-northeast-2"
  cloud_storage_access_key: "..."
  cloud_storage_secret_key: "..."

  # 토픽별 설정도 가능
  # topic level:
  #   retention.ms=604800000 (7일 로컬)
  #   retention.local.target.ms=86400000 (하루만 로컬, 나머지 S3)

“핫 데이터는 로컬, 콜드는 S3” 자동 계층화로 월 저장 비용을 크게 절감하면서 consumer가 오래된 데이터도 정상 접근 가능합니다.

프로덕션 설정

인증·인가

# SASL/SCRIPT-SHA256 활성
rpk cluster config set enable_sasl true
rpk cluster config set superusers "admin"

rpk acl user create admin -p strong-password

# 일반 사용자
rpk acl user create alice -p alice-password
rpk acl create --allow-principal User:alice --operation read --topic orders
rpk acl create --allow-principal User:alice --operation write --topic orders

# 클라이언트 연결
rpk topic produce orders -X user=alice -X pass=alice-password -X sasl.mechanism=SCRAM-SHA-256

TLS

redpanda:
  kafka_api_tls:
    - name: external
      enabled: true
      cert_file: /etc/redpanda/certs/tls.crt
      key_file: /etc/redpanda/certs/tls.key
      require_client_auth: false

토픽 보존·압축

rpk topic create events \
  --partitions 12 --replicas 3 \
  --config retention.ms=604800000 \
  --config compression.type=zstd \
  --config cleanup.policy=delete

# compact (키 최신값 유지)
rpk topic create user-profiles \
  --config cleanup.policy=compact \
  --config segment.ms=3600000

Kafka에서 마이그레이션

방법 1: MirrorMaker 2

# mm2.properties
clusters = source, target
source.bootstrap.servers = kafka-old:9092
target.bootstrap.servers = redpanda:9092

source->target.enabled = true
source->target.topics = .*
bin/connect-mirror-maker.sh mm2.properties

방법 2: Redpanda Connect

input:
  kafka_franz:
    seed_brokers: ["kafka-old:9092"]
    topics: [".*"]
    regexp_topics: true
    consumer_group: "mirror"

output:
  kafka_franz:
    seed_brokers: ["redpanda:9092"]
    topic: "${! meta(\"kafka_topic\") }"

방법 3: 애플리케이션 cutover

트래픽을 Redpanda에도 dual-write → consumer를 Redpanda로 전환 → 기존 Kafka의 dual-write 제거. 가장 안전하지만 시간이 걸립니다.

벤치마크 체크리스트

Kafka 대비 실제 이득 측정:

# Redpanda
rpk benchmark --brokers redpanda:9092 --topic bench \
  --producers 10 --consumers 10 --records 10000000 --size 1024

# Kafka
kafka-producer-perf-test.sh --topic bench --num-records 10000000 \
  --record-size 1024 --throughput -1 --producer-props bootstrap.servers=kafka:9092

비교 대상:

  • 평균/최대 처리량
  • p50/p95/p99 publish 지연
  • consumer lag
  • CPU·메모리 사용

많은 조직이 “동일 하드웨어에서 2-6배 처리량, p99 지연 1/10”을 얻는 것을 보고합니다.

문제 해결

브로커가 under-replicated 상태

  • Raft 복제가 따라가지 못함 → 네트워크·디스크 확인
  • rpk cluster health 로 상세 확인
  • 단일 노드에서 다시 balance 되도록 rpk cluster partitions movement status

Produce 실패 not_enough_replicas

  • min.insync.replicas 설정과 실제 복제본 수 확인
  • rpk topic describe TOPIC 로 ISR 확인

Consumer lag 증가

  • 컨슈머 그룹 처리 성능 문제. Prometheus의 kafka_consumer_lag 확인
  • 파티션 수가 적으면 병렬성 부족 → 토픽 파티션 증가(기존 데이터는 재분배 안 됨 유의)

Tiered Storage 업로드 실패

  • S3 자격 증명·버킷 권한
  • cloud_storage_max_connections 조정

JVM Kafka 클라이언트가 연결 안 됨

  • Kafka 프로토콜 버전 협상 로그 확인
  • Redpanda가 지원하지 않는 API 호출 시 UNSUPPORTED_VERSION 반환

모니터링

  • Prometheus endpoint: :9644/metrics
  • 핵심 메트릭: vectorized_raft_leader(shard별 리더 여부), vectorized_kafka_quotas_client_quotas, vectorized_storage_log_*
  • 공식 Grafana 대시보드 제공
  • Redpanda Console에서 실시간 토픽·컨슈머 모니터링

언제 Kafka를 유지해야 하나

  • Confluent Platform 독점 기능 의존: Stream Designer, 특정 커넥터
  • 대규모 Kafka Streams 파이프라인: 테스트·검증 비용이 큼
  • 팀의 Kafka 운영 경험이 풍부: 이미 잘 돌고 있다면 리스크 감수 불필요
  • Redpanda 에코시스템 미지원 도구: 일부 엔터프라이즈 도구

그 외 대부분은 점진적 도입·부분 교체로 이점을 취할 수 있습니다.

체크리스트

  • 토픽 설계: 파티션·복제·보존·압축
  • SASL + ACL + TLS로 보안
  • Tiered Storage로 장기 보존 비용 절감
  • 스키마 레지스트리로 이벤트 계약 강제
  • Redpanda Connect로 CDC·싱크 구성
  • Prometheus + Grafana 대시보드
  • Console UI로 운영자 편의성 확보
  • 재해복구: 두 리전 간 MM2/Connect 미러링
  • rpk로 운영 자동화(IaC 연동)

마무리

Redpanda는 “Kafka 생태계의 가치는 유지하면서 운영 복잡성은 제거한다”는 합리적 절충안으로 2024-2026년 가파르게 채택되고 있습니다. 이벤트 드리븐 아키텍처를 새로 시작하는 팀이라면 ZooKeeper/KRaft 없이 단일 바이너리로 시작할 수 있다는 장점이 결정적이고, 기존 Kafka를 운영하는 팀도 p99 지연·운영 인력을 실측해본 뒤 전환 ROI를 계산해볼 가치가 충분합니다. 대부분의 Kafka 클라이언트·도구를 그대로 쓰면서 인프라만 교체하는 “조용한 마이그레이션”이 가능하다는 점이 Redpanda의 가장 큰 매력입니다.

관련 글

  • Kafka 완벽 가이드
  • 이벤트 드리븐 아키텍처 가이드
  • NATS 메시징 완벽 가이드
  • RabbitMQ 완벽 가이드