백엔드 데이터 인프라 82편 — Kafka Quickstart (5분 hands-on · topic·producer·consumer)

2026-05-17백엔드 데이터 인프라

백엔드 데이터 인프라 82편. Kafka Quickstart — 로컬에 KRaft 모드 단일 노드 띄우고 topic 만들고 producer/consumer 직접 실행하는 5분 hands-on. Docker·다운로드 방식 둘 다, 시리즈 1 Spring 환경에서 바로 이어 갈 수 있게 풀어쓴 학습 노트.

📚 백엔드 데이터 인프라 · 82편 — Kafka Quickstart (5분 hands-on · topic·producer·consumer)

이 글은 백엔드 데이터 인프라 시리즈 130편 중 82편이에요. 80~81편 으로 Kafka 의 정체성과 활용 영역을 잡았다면, 82편은 직접 손으로 짚는 차례 — 로컬에 Kafka 한 노드 띄우고 topic·producer·consumer 까지 5분 hands-on 으로 끝낸다.

왜 hands-on부터 짚어야 하나

83~89편 Design 영역으로 들어가기 전에 몸으로 한 번 익혀 두면 추상 개념이 훨씬 잘 박힌다. Producer·Consumer 가 어떤 흐름인지 터미널에서 직접 보고, Topic·Partition 의 실제 모양을 확인하고, Consumer Group(같은 그룹 안 consumer 들이 partition 을 나눠 받는 단위) 동작을 직접 관찰한 뒤, Java 클라이언트 코드 마지막 단계만 추가하면 시리즈 1 Spring 환경으로 자연스럽게 이어진다.

이 글에서 두 가지 방법(다운로드·Docker) + 기본 명령어 4개 + Java 클라이언트 미리보기까지 한 번에 짚는다.

사전 준비

  • Java 17+ 필요 (Kafka 4.0 기준)
  • 또는 Docker (Java 설치 없이)
  • 디스크 약 1GB
  • 메모리 약 2GB

방법 1: 다운로드 방식

Step 1: Kafka 다운로드

$ wget https://downloads.apache.org/kafka/4.0.0/kafka_2.13-4.0.0.tgz
$ tar -xzf kafka_2.13-4.0.0.tgz
$ cd kafka_2.13-4.0.0

폴더 구조:

bin/        - 모든 CLI 도구 (.sh 파일)
config/     - 설정 파일
libs/       - JAR 의존성

Step 2: KRaft 모드 시작

Kafka 4.0+ 는 Zookeeper 없이 KRaft(Kafka 자체 합의 프로토콜) 모드로 돈다. 80편에서 본 Zookeeper 의 후속.

# Cluster UUID 생성 (한 번만)
$ KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"

# 로그 디렉토리 포맷
$ bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties

# Kafka 서버 시작 (foreground)
$ bin/kafka-server-start.sh config/server.properties

성공하면 수십 줄 로그 후 다음 메시지가 뜬다.

[KafkaServer id=1] started (kafka.server.KafkaServer)

이제 로컬 localhost:9092 에서 Kafka 가 듣고 있어요.

Step 3: 새 터미널 — Topic 만들기

$ bin/kafka-topics.sh --create \
    --topic quickstart-events \
    --bootstrap-server localhost:9092 \
    --partitions 3 \
    --replication-factor 1

Created topic quickstart-events.
  • --partitions 3 = 3개 partition
  • --replication-factor 1 = 단일 노드라 1 (운영 환경은 3)

확인:

$ bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092

Topic: quickstart-events  TopicId: ...  PartitionCount: 3  ReplicationFactor: 1
    Topic: quickstart-events  Partition: 0  Leader: 1  Replicas: 1  Isr: 1
    Topic: quickstart-events  Partition: 1  Leader: 1  Replicas: 1  Isr: 1
    Topic: quickstart-events  Partition: 2  Leader: 1  Replicas: 1  Isr: 1

방법 2: Docker — 가장 빠른 시작

Java 설치 없이 한 줄로 띄운다.

$ docker run -d --name kafka \
    -p 9092:9092 \
    apache/kafka:4.0.0

Topic 만들기:

$ docker exec -it kafka \
    /opt/kafka/bin/kafka-topics.sh --create \
    --topic quickstart-events \
    --bootstrap-server localhost:9092 \
    --partitions 3

이후 모든 명령은 docker exec -it kafka /opt/kafka/bin/<command> 형태로 들어간다.

Step 4: Producer — 이벤트 보내기

$ bin/kafka-console-producer.sh \
    --topic quickstart-events \
    --bootstrap-server localhost:9092

>Hello
>World
>This is event 3

> 프롬프트에서 한 줄이 한 이벤트. Ctrl+C 로 종료한다.

시험 함정 하나 — kafka-console-producer.sh 의 기본 동작은 key 없이 value 만 박히고 partition 은 라운드 로빈으로 돈다. key 까지 박으려면 --property "parse.key=true"--property "key.separator=:" 를 붙인다.

$ bin/kafka-console-producer.sh \
    --topic quickstart-events \
    --bootstrap-server localhost:9092 \
    --property "parse.key=true" \
    --property "key.separator=:"

>user42:Made a payment
>user99:Logged in

이제 user42 의 이벤트는 같은 partition 으로 떨어진다 (key hash 기반).

Step 5: Consumer — 이벤트 받기

$ bin/kafka-console-consumer.sh \
    --topic quickstart-events \
    --from-beginning \
    --bootstrap-server localhost:9092

Hello
World
This is event 3

--from-beginning 은 topic 의 모든 메시지를 처음부터 끌어온다. 생략하면 현재 시점 이후 메시지만 본다.

key 까지 보기:

$ bin/kafka-console-consumer.sh \
    --topic quickstart-events \
    --from-beginning \
    --bootstrap-server localhost:9092 \
    --property "print.key=true" \
    --property "key.separator=:"

user42:Made a payment
user99:Logged in

Step 6: Consumer Group 관찰

새 터미널 두 개 열고 같은 그룹으로 붙인다.

# Terminal A
$ bin/kafka-console-consumer.sh --topic quickstart-events --bootstrap-server localhost:9092 --group group-1

# Terminal B (같은 그룹)
$ bin/kafka-console-consumer.sh --topic quickstart-events --bootstrap-server localhost:9092 --group group-1

같은 --group group-1 인 두 consumer 는 partition 을 나눠 받는다. Partition 3개에 consumer 2명이면 한 명이 2개 partition, 다른 한 명이 1개를 맡는 식.

다른 그룹은 독립적으로 모든 메시지를 받는다.

# Terminal C (다른 그룹)
$ bin/kafka-console-consumer.sh --topic quickstart-events --bootstrap-server localhost:9092 --group group-2

group-2 는 처음부터 (또는 현재부터) 모든 메시지를 다시 받는다.

Consumer group 상태 확인:

$ bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group group-1

GROUP    TOPIC              PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG
group-1  quickstart-events  0          5               5               0
group-1  quickstart-events  1          3               3               0
group-1  quickstart-events  2          2               2               0
  • CURRENT-OFFSET = consumer 가 처리한 마지막 offset
  • LOG-END-OFFSET = topic 의 마지막 offset
  • LAG = 남은 미처리 = LOG-END-OFFSET - CURRENT-OFFSET

운영 모니터링에서 가장 핵심 메트릭이 이 lag.

Step 7: Topic 정리·삭제

# 모든 topic 목록
$ bin/kafka-topics.sh --list --bootstrap-server localhost:9092

# topic 삭제
$ bin/kafka-topics.sh --delete --topic quickstart-events --bootstrap-server localhost:9092

Java 클라이언트 미리보기 — Spring Boot

// 의존성
// implementation 'org.springframework.kafka:spring-kafka'

// Producer
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;

public void sendEvent(String key, String value) {
    kafkaTemplate.send("quickstart-events", key, value);
}

// Consumer
@KafkaListener(topics = "quickstart-events", groupId = "spring-group")
public void listen(String message) {
    System.out.println("Received: " + message);
}
spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: spring-group
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer

이것만으로 시리즈 1 Spring Boot 환경에서 Kafka 통합이 시작된다. 130편 Spring Kafka 에서 더 깊이 들어간다.

자주 막히는 자리

1. "Connection refused" 에러

Kafka 서버가 안 떠 있다. kafka-server-start.sh 로그를 확인한다.

2. "Topic does not exist" 에러

Auto-create 가 꺼진 환경이거나 topic 을 안 만들었다. 명시적으로 create 하거나 auto.create.topics.enable=true 로 켠다 (개발용).

3. "Marking the coordinator dead" 에러

Consumer group coordinator 통신 문제. bootstrap server 주소·방화벽·hostname 해상도를 확인한다.

4. Consumer 가 메시지를 못 받음

기본은 consumer 시작 이후 메시지만 받는다. --from-beginning 또는 auto.offset.reset=earliest 로 바꾼다.

5. partition 보다 많은 consumer

여기가 정말 중요한 자리 — partition 3개에 consumer 5명이면 2명은 놀고 있다. partition 수 ≥ consumer 수 가 일반 원칙.

다음 단계 — 무엇을 더 해볼까

Quickstart 끝났다면:

  1. Java 클라이언트 로 producer/consumer 직접 작성 (90~93편)
  2. 여러 broker 띄우고 replication 관찰 (107편 replication 깊이)
  3. Kafka Streams 로 간단한 처리 파이프라인 (121~129편)
  4. Confluent Cloud 같은 Managed Kafka 무료 plan 체험

시험 직전 한 번 더 — Kafka Quickstart 함정 압축 노트

  • 사전 준비 = Java 17+ 또는 Docker
  • Kafka 4.0+ = KRaft 모드 (Zookeeper 없음)
  • 시작 = kafka-storage.sh formatkafka-server-start.sh
  • Cluster UUID = kafka-storage.sh random-uuid (한 번만)
  • Topic 생성 = kafka-topics.sh --create --topic <name> --partitions N --replication-factor M
  • Topic 정보 = kafka-topics.sh --describe --topic <name>
  • Producer = kafka-console-producer.sh --topic <name>
  • 기본 producer = key 없음, value 만, partition 라운드 로빈
  • key 박기 = --property "parse.key=true" + --property "key.separator=:"
  • Consumer = kafka-console-consumer.sh --topic <name>
  • --from-beginning = 처음부터 모든 메시지
  • key 보기 = --property "print.key=true"
  • Consumer Group = 같은 --group = partition 나눠 받음
  • 다른 group = 독립적 모든 메시지 받음
  • kafka-consumer-groups.sh --describe = lag 모니터링
  • LAG = 미처리 메시지 수 (가장 중요한 메트릭)
  • 일반 원칙 — partition 수 ≥ consumer 수
  • partition > consumer = 일부 consumer 가 여러 partition 처리
  • partition < consumer = 일부 consumer 가 놀고 있음
  • Docker = apache/kafka:4.0.0 이미지
  • Spring Boot 통합 = spring-kafka 의존성 + @KafkaListener·KafkaTemplate
  • 자주 에러 — connection refused, topic does not exist, coordinator dead, from-beginning 누락

공식 문서: Apache Kafka Quickstart 에서 자세한 사양과 다른 시나리오를 확인할 수 있어요.

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!