Skip to main content
결제 완료 record를 보냈는데, Kafka 안에서는 무엇이 생겼는지 직접 보고 싶어요.
앞 글에서 kafka-docker와 kafka-ubuntu VM을 같은 profile로 준비했어요. 그보다 앞에서는 Kafka를 “메시지를 건네고 없애는 우체통”보다 “partition에 이어지는 기록”으로 바라봤고요. 이번에는 그 그림을 터미널에서 확인해볼게요. 로컬 broker 하나를 실행하고, orders.paid topic에 record를 남긴 뒤 다시 읽어요. Broker를 재시작해도 같은 record를 읽을 수 있는지까지 확인합니다.
이 실습은 Apache Kafka 4.3.1을 기준으로 해요. Docker 트랙은 Docker Engine 29.5.3과 공식 apache/kafka:4.3.1 image를, 직접 설치 트랙은 Ubuntu 22.04 LTS aarch64, OpenJDK 21.0.11, kafka_2.13-4.3.1.tgz를 사용해요. 앞 글의 Ubuntu 26.04 LTS amd64 VM에서도 같은 Kafka 4.3.1과 Java 21 조합을 사용해요.

시작하기 전에 환경을 확인해요

이번 실습은 학습용 단일 node예요. 한 process가 broker와 KRaft controller 역할을 함께 맡아요. 여러 broker에 복제하는 production cluster와는 장애 범위가 달라요.
2 GB는 Kafka의 production 용량 기준이 아니에요. 이번 실습에서 image 또는 binary와 작은 log를 담기 위한 여유예요. 실제 보관 용량은 record 크기, 유입량, retention, replication에 맞춰 별도로 계산해야 해요. 두 VM은 tooling-ready snapshot에서 시작해야 해요. 이전 실행에서 aha-kafka container, orders.paid topic, $HOME/kafka-data가 이미 생겼다면 snapshot을 복원하거나 기존 상태가 필요한지 먼저 판단하세요.

두 VM에서 같은 결과를 확인해요

작성할 때는 두 경로를 모두 검증해요. 학습할 때는 한 탭을 끝낸 뒤 다른 VM에서 같은 순서를 반복하면 됩니다. 둘 다 metadata, produce, consume, restart를 같은 fixture로 확인해요.
1

Port와 Docker 상태를 확인해요

먼저 Docker daemon이 응답하는지 확인해요.
9092 port를 이미 사용하는 process가 있다면 종료하거나 다른 실습 환경을 골라야 해요.
아무 줄도 나오지 않으면 9092를 사용할 수 있어요.
2

공식 image로 broker를 실행해요

Version이 움직이지 않도록 latest 대신 4.3.1 tag를 고정해요.
-p 9092:9092는 host의 localhost:9092를 container의 listener에 연결해요. 이 단일 container 실습에서는 별도 Docker network가 필요하지 않아요.Broker log가 궁금하면 다음 명령으로 따라가요. 시작이 끝나면 Ctrl+C로 log 보기만 종료할 수 있어요.
3

Metadata 요청으로 broker 상태를 확인해요

“Container가 실행 중”과 “Kafka가 요청에 응답함”은 다른 상태예요. Topic 목록 요청이 성공하는지 확인해요.
처음에는 topic 이름이 없어 빈 결과가 나올 수 있어요. 오류 없이 끝났다면 broker가 metadata 요청에 응답한 거예요.
4

Topic을 만들고 partition을 확인해요

첫 실습은 record의 위치를 한 줄로 보기 위해 partition 하나를 사용해요.
설명에서 PartitionCount: 1과 ReplicationFactor: 1을 확인해요. 복제본 하나는 현재 broker 하나에만 있으므로 broker 자체가 사라지는 장애를 견디는 구성은 아니에요.
5

첫 record를 왕복해요

Console producer에서 입력한 한 줄이 record 하나가 돼요.
> prompt가 보이면 아래 JSON 한 줄을 붙여 넣고 Enter, Ctrl+C를 차례로 눌러요.
이제 log의 처음부터 한 record만 읽어요.
JSON 앞에 Partition:0과 Offset:0이 보이면 record 하나가 partition 0의 첫 위치에 저장된 거예요.
6

Broker를 재시작하고 다시 읽어요

같은 container를 재시작한 뒤 metadata 요청과 consume을 다시 실행해요.
같은 JSON이 다시 보이면 broker process가 재시작되어도 log data를 다시 연 거예요.
Topic 설명에서 partition 0이 보이고, producer가 보낸 JSON을 consumer가 Partition:0, Offset:0에서 읽었으며, broker 재시작 뒤에도 같은 JSON을 다시 읽었다면 실습이 끝났어요.

방금 일어난 일을 그림으로 연결해요

Producer가 받은 응답은 broker가 record를 받아들였다는 뜻이에요. 배송 업무가 끝났다는 뜻은 아니에요. Consumer도 poll, 업무 처리, 읽기 위치 저장을 서로 다른 경계로 다뤄야 해요. 이번 console consumer는 그중 record를 가져오는 모습을 보여줬어요. --from-beginning으로 새 consumer를 다시 실행했기 때문에 같은 record를 또 읽을 수 있었어요. Record는 누군가 한 번 출력했다고 바로 지워지지 않아요. Topic의 retention 범위 안에서 log에 남아요.

Port, listener, network는 왜 자주 막힐까요?

--bootstrap-server localhost:9092는 첫 연결 주소예요. Client는 이 주소로 cluster metadata를 받은 뒤, broker가 알려준 advertised listener 주소로 실제 연결을 이어가요. 이번 단일 node 예제에서는 host와 container가 모두 localhost:9092를 사용할 수 있도록 공식 image의 기본값과 port mapping을 그대로 사용했어요. Client를 다른 container나 다른 computer로 옮기면 localhost가 가리키는 곳이 달라져요. 그때는 Docker network에서 해석 가능한 broker 이름과 host에서 접근 가능한 advertised listener를 분리해서 설계해야 해요.
이 실습은 인증과 암호화가 없는 local PLAINTEXT 연결이에요. Production에서는 network 경계, TLS, 인증, 여러 broker의 listener와 advertised listener를 함께 설계해야 해요.

Data를 지우면 무엇이 사라질까요?

Docker 경로는 **같은 container를 docker restart**했을 때 container filesystem의 log를 다시 열어요. docker rm으로 container를 제거하면 그 실습 data도 함께 잃는다고 생각하는 편이 안전해요. 장기간 유지할 cluster라면 명시적인 volume과 log.dirs 설정, backup과 recovery 절차가 필요해요. Ubuntu 직접 설치 경로는 config/server.properties의 log.dirs를 $HOME/kafka-data로 바꿨어요. VM을 재시작해도 home directory가 남아 있는 동안 record와 consumer offset을 다시 열 수 있어요. Production에서는 별도 service user와 용량·권한을 관리할 전용 filesystem을 설계해야 해요.
아래 명령은 실습 container와 그 안의 Kafka data를 제거해요. orders.paid record가 더 필요하지 않을 때만 실행하세요.
직접 설치의 data directory는 위치를 config/server.properties에서 확인하기 전까지 삭제하지 마세요. 경로를 확인한 뒤에도 필요한 record와 consumer offset을 backup했는지 먼저 판단해야 해요.

막히면 이 순서로 살펴봐요

lsof -nP -iTCP:9092 -sTCP:LISTEN으로 process를 확인해요. 기존 broker를 의도적으로 사용하려는 것이 아니라면 먼저 종료하고 다시 시작하세요. Docker port만 바꾸면 advertised listener와 client 주소도 함께 맞춰야 하므로 처음 실습에서는 빈 9092를 쓰는 편이 덜 헷갈려요.
Container 상태만 보지 말고 sudo docker logs aha-kafka 또는 직접 설치의 broker log를 확인해요. 시작이 끝나기 전에 client 명령을 보냈거나, listener가 client가 접근할 수 없는 주소를 advertise했을 수 있어요.
java -version과 echo "$JAVA_HOME"을 확인해요. Kafka 4.3.1 quickstart는 Java 17 이상을 요구해요. 여러 Java가 설치되어 있다면 shell이 실제로 어느 java를 실행하는지 command -v java로 확인하세요.
직접 설치 directory와 log.dirs에 현재 사용자가 쓸 수 있는지, df -h로 filesystem 여유가 있는지 확인해요. Docker라면 sudo docker system df로 image와 volume 사용량을 함께 확인하세요. 공간을 확보하려고 volume이나 data directory부터 지우면 record도 함께 사라질 수 있어요.

다음 실습용 snapshot을 남겨요

두 broker를 정상 종료한 뒤 VM snapshot을 만들면 첫 record까지 확인한 상태로 돌아올 수 있어요.
kafka-docker VM에서 container를 멈추고 VM을 종료해요. stop은 container와 data를 지우지 않아요.
두 VM이 shut off 상태가 되면 host에서 virsh로 working-first-record snapshot을 만들어요.
다음 글을 바로 이어갈 때는 virsh --connect qemu:///system start VM_NAME으로 VM을 다시 켜세요. Docker에서는 sudo docker start aha-kafka, Ubuntu 직접 설치에서는 Kafka directory에서 bin/kafka-server-start.sh -daemon config/server.properties를 실행합니다.
두 VM의 snapshot 목록에 working-first-record가 있고, broker를 다시 시작한 뒤 orders.paid의 evt-101을 읽을 수 있다면 다음 실습을 위한 상태가 준비됐어요.

자, 정리해볼까요?

  • Docker와 Ubuntu 직접 설치 모두 KRaft 기반의 learning용 단일 node를 실행할 수 있어요.
  • Metadata 요청 성공, topic 생성, produce, consume은 서로 다른 확인 단계예요.
  • 첫 JSON record는 orders.paid의 partition 0, offset 0에 놓였어요.
  • Broker process를 재시작해도 같은 data directory가 남아 있으면 record를 다시 읽을 수 있어요.
  • Container나 data directory를 삭제하는 cleanup은 restart와 달리 record를 되돌릴 수 없게 지울 수 있어요.

이전 글

두 Ubuntu VM과 tooling-ready snapshot을 준비해요.

다음 글

Key가 record를 어느 partition으로 보내고, 순서를 어디까지 지켜주는지 확인해요.