ZooKeeper에서 KRaft로 — 클러스터 메타데이터 관리의 세대교체
90+ Kafka Interview Questions and Answers (blog) kafka_ref_01(Q10-13)의 최신 서술을 정확한 기준으로 삼아, kafk_ref_02(Q5,Q6,Q16 — 'ZooKeeper 없이는 Kafka 서버에 연결할 수 없다', 'Kafka 서버를 시작하려면 반드시 ZooKeeper를 먼저 띄워야 한다'), kafka_ref_04('Kafka는 3.x대에 KRaft로 이동 중'이라는 진행형 서술), kafka_ref_05(Q1,Q14 — ZooKeeper를 여전히 현재의 표준 아키텍처로, KRaft를 '미래에 없앨 대상'으로 서술)의 오래된 내용을 Kafka 4.0 기준(ZooKeeper 모드 완전 제거)으로 수정.
이 모듈을 다 읽으면
- ZooKeeper가 과거 Kafka에서 수행하던 역할을 설명할 수 있다
- KRaft가 왜 도입되었고 어떤 장점을 제공하는지 설명할 수 있다
- 현재(Kafka 4.x) Kafka 클러스터를 구동하는 데 ZooKeeper가 더 이상 필요하지 않다는 사실과 그 전환 시점(버전)을 정확히 알 수 있다
- 'ZooKeeper 필수'라는 오래된 서술이 왜 더 이상 정확하지 않은지 판단할 수 있다
여러 블로그 자료가 'ZooKeeper 없이는 Kafka에 연결할 수 없다'거나 'Kafka는 여전히 ZooKeeper에 의존한다'고 서술하지만, 이는 KRaft 이전 시대의 설명이다. 이 모듈은 ZooKeeper의 과거 역할과 KRaft로의 전환 과정, 그리고 2026년 현재(Kafka 4.x) 기준 사실 관계를 바로잡아 정리한다.
ZooKeeper가 하던 일 (과거형)
KRaft 이전 Kafka는 클러스터 메타데이터 관리를 외부 ZooKeeper 앙상블에 위임했다. ZooKeeper는 브로커 등록과 생존 여부(heartbeat) 추적, 컨트롤러(파티션 리더 선출과 관리 작업을 담당하는 브로커) 선출, 토픽/파티션 설정 저장 등을 담당했다. 이 구조에서는 컨트롤러 역할을 맡은 브로커 하나가 장애가 나면 ZooKeeper가 남은 브로커 중에서 새 컨트롤러를 선출해주는 방식이었고, 메타데이터 변경이 전파되는 데 초 단위 시간이 걸릴 수 있었다.
한 가지 자주 혼동되는 지점은 컨슈머 오프셋이다 — 아주 초기 버전의 Kafka는 오프셋을 ZooKeeper에 저장했지만, 이후 버전부터는 별도의 내부 토픽인 __consumer_offsets에 저장하도록 바뀌었다. 즉 오프셋 저장은 이미 오래전부터 ZooKeeper의 역할이 아니었다.
핵심 포인트
- ZooKeeper는 브로커 등록, 컨트롤러 선출, 토픽/파티션 메타데이터 저장을 담당했다
- 컨슈머 오프셋은 초기 버전 이후로는 ZooKeeper가 아니라 __consumer_offsets 내부 토픽에 저장된다
- ZooKeeper 기반 메타데이터 전파는 초 단위 지연이 있었다
KRaft로의 전환과 현재 상태 — '필수'가 아니라 '유일한' 모드
일부 블로그 자료(예: DataFlair 스타일 Q&A)는 "ZooKeeper를 우회하고 Kafka 서버에 직접 연결하는 것은 불가능하다"거나, Kafka 서버를 시작하려면 반드시 먼저 zookeeper-server-start.sh를 실행해야 한다고 설명한다. 이는 KRaft 도입 이전에는 맞는 말이었지만, 지금은 정확하지 않다.
KIP-500으로 시작된 KRaft(Kafka Raft) 프로젝트는 Raft 합의 알고리즘을 사용하는 전용 컨트롤러 쿼럼이 클러스터 메타데이터를 자체 내부 토픽(__cluster_metadata)에 저장·복제하도록 만들어, 외부 ZooKeeper 앙상블 없이 Kafka 혼자 메타데이터를 관리할 수 있게 했다. KRaft는 Kafka 3.3에서 프로덕션 준비 완료로 선언되었고, Kafka 4.0(2025년 출시)에서는 ZooKeeper 모드 자체가 코드베이스에서 완전히 제거되었다 — 즉 2026년 현재 신규로 배포하는 Kafka 클러스터는 ZooKeeper 없이 KRaft로만 동작하며, "ZooKeeper가 없으면 Kafka에 연결할 수 없다"는 서술이나 "먼저 ZooKeeper를 시작해야 Kafka 서버를 띄울 수 있다"는 절차는 4.0 이상에서는 더 이상 존재하지 않는 개념이다.
다른 참고 자료 중 일부(예: "Kafka는 3.x대에 KRaft로 이동 중"이라는 서술)도 이미 지나간 과거형으로 다시 읽어야 한다 — "이동 중"이 아니라 "이동 완료 및 ZooKeeper 제거 완료" 상태다. KRaft가 주는 실질적 이점은 밀리초 단위 메타데이터 전파, 서브초 단위의 빠른 컨트롤러 페일오버, 클러스터당 지원 가능한 파티션 수의 대폭 증가(수백만 단위), 그리고 운영·보안 대상이 되는 시스템이 (ZooKeeper + Kafka) 둘에서 Kafka 하나로 줄어드는 단순화다.
핵심 포인트
- KRaft는 KIP-500으로 시작되어 Kafka 3.3에서 프로덕션 준비 완료로 선언되었다
- Kafka 4.0부터는 ZooKeeper 모드가 코드베이스에서 완전히 제거되어 KRaft가 유일한 모드다
- 'ZooKeeper 없이는 Kafka에 연결할 수 없다'는 서술은 KRaft 이전 시대의 오래된 설명이다
- __cluster_metadata라는 내부 토픽에 컨트롤러 쿼럼이 메타데이터를 Raft로 복제·저장한다
- KRaft는 메타데이터 전파 속도, 컨트롤러 페일오버 속도, 지원 파티션 수, 운영 단순성에서 모두 ZooKeeper 방식보다 낫다
컨트롤러의 역할 — ZooKeeper 시대 vs KRaft 시대
컨트롤러는 파티션 리더 선출, 브로커 간 파티션 분배, 토픽 생성/삭제 같은 관리 작업을 담당하는 클러스터의 핵심 역할이다. ZooKeeper 시대에는 브로커 중 하나가 컨트롤러 역할을 겸했고, 장애 시 ZooKeeper가 나머지 브로커 중에서 새 컨트롤러를 선출하도록 도왔다.
KRaft 시대에는 (작은 클러스터에서는 브로커 역할과 결합될 수도 있는) 전용 컨트롤러 노드들이 Raft 합의로 쿼럼을 이루며, 활성 컨트롤러 하나와 즉시 대체 가능한 대기 컨트롤러들이 외부 시스템 없이 스스로 관리된다. 브로커가 다운되면 KRaft 컨트롤러가 하트비트 유실로 이를 감지하고, 해당 브로커가 리더였던 모든 파티션에 대해 ISR 중에서 새 리더를 선출하며, 프로듀서/컨슈머는 메타데이터를 갱신해 새 리더로 자동 전환한다. 따라서 "컨트롤러 장애 감지가 ZooKeeper 또는 KRaft 하트비트 타임아웃을 통해 이뤄진다"처럼 두 메커니즘을 병기하는 서술은 현재는 부정확하며, 현재 유일한 메커니즘은 KRaft 컨트롤러 쿼럼의 하트비트 추적이다.
핵심 포인트
- 컨트롤러는 리더 선출·파티션 분배·토픽 관리 등 클러스터 운영을 담당한다
- ZooKeeper 시대는 브로커 중 하나가 컨트롤러 역할을 겸했다
- KRaft 시대는 전용 컨트롤러 쿼럼이 활성/대기 구조로 스스로 페일오버한다
- 현재는 컨트롤러 장애 감지 메커니즘이 KRaft 하나뿐이며 ZooKeeper 병기 서술은 오래된 설명이다