Kafka 4.0의 KRaft: 이제 ZooKeeper, 쿼럼 컨트롤러 및 마이그레이션
Kafka 4.0(2025년 3월)은 KRaft와 3년 동안 공존한 후 ZooKeeper를 영구적으로 제거했습니다. 이 심층 가이드에서는 새로운 Raft 기반 쿼럼 컨트롤러인 Path의 작동 방식을 설명합니다. Kafka 3.x에서 오는 필수 마이그레이션, 실제 운영상의 이점과 함정 생산으로 전환하는 동안에는 피해야 합니다.
ZooKeeper의 문제
거의 10년 동안 모든 Apache Kafka 클러스터에는 앙상블이 필요했습니다. 아파치 주키퍼 메타데이터 관리를 위해 별도로: 어떤 브로커가 활성 상태인지, 어떤 브로커가 어떤 파티션, 주제 및 ACL 메타데이터의 리더인지를 나타냅니다. ZooKeeper는 조정 시스템입니다. 강력하고 안정적으로 분산되었지만 여러 가지 중요한 운영 문제가 발생했습니다.
- 이중 운영 복잡성: Kafka를 관리하는 각 팀은 별도의 ZooKeeper 클러스터도 관리해야 했습니다. (일반적으로 3개 또는 5개 노드), 자체 모니터링, 업그레이드 주기 및 고유한 구성이 있습니다.
- 제한된 메타데이터 확장성: ZooKeeper는 ~200,000개의 파티션을 넘어서는 성능 저하를 보였습니다. 각 파티션의 메타데이터가 별도의 ZooKeeper 노드로 기록되었기 때문입니다.
- 느린 컨트롤러 선택: Kafka 브로커 컨트롤러가 다운되면 새 컨트롤러는 정수를 읽어야 했습니다. 대규모 클러스터의 경우 수십 초가 걸릴 수 있는 프로세스가 작동하기 전에 ZooKeeper에서 클러스터 상태를 가져옵니다.
- 재해 복구의 어려움: ZooKeeper에서 데이터 손실이 발생한 경우 Kafka 클러스터 복구 이는 복잡하고 위험한 수동 프로세스였습니다.
KRaft 타임라인
- KIP-500 (2020): Kafka에서 ZooKeeper를 제거하라는 원래 제안
- 카프카 2.8 (2021년 4월): KRaft의 초기 액세스 버전이 포함된 첫 번째 버전(테스트용)
- 카프카 3.3 (2022년 10월): KRaft는 새로운 클러스터에 대한 프로덕션 준비를 선언했습니다.
- 카프카 3.5 (2023년 6월): ZooKeeper에서 KRaft로의 마이그레이션 도구 사용 가능
- 카프카 3.7 (2024년 3월): ZooKeeper 모드 지원 중단
- 카프카 4.0 (2025년 3월): ZooKeeper 모드가 영구적으로 제거되었습니다.
KRaft 작동 방식: Raft 합의 로그
메타데이터 로그의 개념
KRaft(Kafka Raft)에 채택된 솔루션은 우아합니다. 메타데이터를 외부 시스템에 의존하는 대신,
Kafka는 메타데이터를 다음과 같이 처리합니다. 내부 Kafka 주제 ~라고 불리는 @metadata.
이 주제는 컨트롤러 노드 간 Raft 프로토콜을 통해 복제됩니다.
KRaft에서 클러스터 브로커는 두 가지 역할 중 하나(또는 소규모 클러스터에서는 둘 다)를 수행합니다.
- 컨트롤러: 클러스터 메타데이터를 관리합니다. 프로덕션 클러스터에서는 3개의 컨트롤러로 구성된 쿼럼이 권장됩니다. 활성 컨트롤러(Raft 리더)는 모든 메타데이터 변경 사항을 처리하고 이를 다른 컨트롤러에 복제합니다.
- 브로커: 파티션 로그를 관리하고 생산자와 소비자에게 서비스를 제공합니다. 브로커는 사본을 보관합니다. 스트리밍에서 업데이트되는 컨트롤러로부터 수신된 메타데이터 캐시입니다.
Kafka의 Raft 프로토콜
Raft는 (Paxos와 달리) 이해 가능하도록 설계된 분산 합의 알고리즘입니다. 간단히 말해서, 모든 쿼럼 노드 중에서 하나가 선출됩니다. 지도자. 리더는 모든 성경을 받고, 이를 팔로어에게 전파하고 대다수의 노드가 쓰기를 확인하면 커밋된 것으로 간주합니다.
KRaft에서는 다음과 같이 번역됩니다.
- 메타데이터 작업(주제 생성, 파티션 리더 할당 등)이 리더 컨트롤러에 도착합니다.
- 리더 컨트롤러는 작업을 직렬화된 이벤트로 메타데이터 로그에 기록합니다.
- 이벤트는 프로토콜을 통해 컨트롤러 팔로어에 복제됩니다.
FETCH(기존 Kafka 코드 활용) - 대다수의 컨트롤러가 확인(쿼럼)되면 작업이 커밋됩니다.
- 브로커는 다음을 통해 활성 컨트롤러에서 푸시된 메타데이터 업데이트를 받습니다.
MetadataUpdate
# Struttura di una directory dati KRaft (broker+controller combinato)
# /var/lib/kafka/data/
/var/lib/kafka/data/
meta.properties # cluster.id, node.id, version
__cluster_metadata-0/ # il metadata log (partizione 0)
00000000000000000000.log
00000000000000000000.index
00000000000000000000.timeindex
leader-epoch-checkpoint
ordini-effettuati-0/ # log di una partizione normale
ordini-effettuati-1/
...
# meta.properties esempio:
node.id=1
version=1
cluster.id=MkU3OEVBNTcwNTJENDM2Qk
쿼럼 컨트롤러: 크기 조정
쿼럼 컨트롤러는 합의 규칙을 따릅니다. f 실패, 필요하다 2f+1 매듭.
- 컨트롤러 3개: 1개의 실패를 허용합니다. (프로덕션을 위한 최소 구성)
- 컨트롤러 5개: 2개의 동시 오류를 허용합니다(중요한 클러스터에 권장).
- 컨트롤러 1개: 로컬 개발/테스트 전용, 내결함성 없음
컨트롤러는 다음과 같습니다. 헌신적인 (컨트롤러 역할만, 사용자 파티션은 관리하지 않음) 또는 결합된 (브로커 역할도 하는 동일한 시스템) 소규모 클러스터(브로커 10개 미만)의 경우 컨트롤러 결합하면 괜찮습니다. 대규모 또는 처리량이 높은 클러스터의 경우 전용 컨트롤러가 관리 부하를 격리합니다. 파티션 I/O 로드의 메타데이터입니다.
처음부터 KRaft 클러스터 구성
# server.properties per un nodo controller+broker combinato (cluster single-node per dev)
# ─── Identity ─────────────────────────────────────────────────────────────────
# In KRaft ogni nodo ha un node.id unico nel cluster (sostituisce broker.id)
node.id=1
# Ruoli: "broker" | "controller" | "broker,controller"
process.roles=broker,controller
# Indirizzo del quorum controller: formato node.id@host:port
controller.quorum.voters=1@localhost:9093
# ─── Listeners ────────────────────────────────────────────────────────────────
# KAFKA: listener per producer/consumer
# CONTROLLER: listener per comunicazione KRaft interna
listeners=KAFKA://localhost:9092,CONTROLLER://localhost:9093
advertised.listeners=KAFKA://localhost:9092
listener.security.protocol.map=KAFKA:PLAINTEXT,CONTROLLER:PLAINTEXT
inter.broker.listener.name=KAFKA
controller.listener.names=CONTROLLER
# ─── Storage ──────────────────────────────────────────────────────────────────
log.dirs=/var/lib/kafka/data
# ─── Replication defaults ─────────────────────────────────────────────────────
default.replication.factor=1 # 1 per dev, 3 per produzione
min.insync.replicas=1 # 1 per dev, 2 per produzione
offsets.topic.replication.factor=1
# ─── Retention ────────────────────────────────────────────────────────────────
log.retention.hours=168 # 7 giorni
log.segment.bytes=1073741824 # 1GB per segmento
# Inizializzare il cluster KRaft (una tantum)
# Step 1: generare un cluster UUID univoco
KAFKA_CLUSTER_ID=$(kafka-storage.sh random-uuid)
echo "Cluster ID: $KAFKA_CLUSTER_ID"
# Step 2: formattare la directory storage con il cluster ID
kafka-storage.sh format \
--config /etc/kafka/server.properties \
--cluster-id "$KAFKA_CLUSTER_ID"
# Output:
# Formatting /var/lib/kafka/data with metadata.version 4.0-IV3.
# Step 3: avviare il broker
kafka-server-start.sh /etc/kafka/server.properties
중요: 클러스터 ID는 변경할 수 없습니다.
Il cluster.id 형식이 파일에 기록될 때 생성됨 meta.properties 각 노드의
그리고 메타데이터 로그에 있습니다. 초기화 후에는 변경할 수 없습니다. 이 파일을 잃어버렸고 노드를 추가하려는 경우
기존 클러스터에 연결하려면 적절한 부트스트랩 절차를 사용해야 합니다. 비밀 관리 시스템에 클러스터 ID를 저장합니다.
Docker Compose: 로컬 개발을 위한 KRaft 클러스터
# docker-compose.yml per cluster Kafka 4.0 KRaft (3 broker)
# Immagine: apache/kafka:4.0.0 (immagine ufficiale Apache, non Confluent)
version: "3.9"
services:
kafka1:
image: apache/kafka:4.0.0
container_name: kafka1
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: "broker,controller"
KAFKA_LISTENERS: "PLAINTEXT://kafka1:9092,CONTROLLER://kafka1:9093"
KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka1:9092"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka1:9093,2@kafka2:9093,3@kafka3:9093"
KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
KAFKA_DEFAULT_REPLICATION_FACTOR: 3
KAFKA_MIN_INSYNC_REPLICAS: 2
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
volumes:
- kafka1-data:/var/lib/kafka/data
kafka2:
image: apache/kafka:4.0.0
container_name: kafka2
environment:
KAFKA_NODE_ID: 2
KAFKA_PROCESS_ROLES: "broker,controller"
KAFKA_LISTENERS: "PLAINTEXT://kafka2:9092,CONTROLLER://kafka2:9093"
KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka2:9092"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka1:9093,2@kafka2:9093,3@kafka3:9093"
KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
KAFKA_DEFAULT_REPLICATION_FACTOR: 3
KAFKA_MIN_INSYNC_REPLICAS: 2
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
volumes:
- kafka2-data:/var/lib/kafka/data
kafka3:
image: apache/kafka:4.0.0
container_name: kafka3
environment:
KAFKA_NODE_ID: 3
KAFKA_PROCESS_ROLES: "broker,controller"
KAFKA_LISTENERS: "PLAINTEXT://kafka3:9092,CONTROLLER://kafka3:9093"
KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka3:9092"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka1:9093,2@kafka2:9093,3@kafka3:9093"
KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
KAFKA_DEFAULT_REPLICATION_FACTOR: 3
KAFKA_MIN_INSYNC_REPLICAS: 2
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
volumes:
- kafka3-data:/var/lib/kafka/data
volumes:
kafka1-data:
kafka2-data:
kafka3-data:
ZooKeeper를 사용하여 Kafka 3.x에서 KRaft로 마이그레이션
ZooKeeper 모드에서 Kafka 3.x 클러스터를 관리하고 KRaft로 마이그레이션해야 하는 경우(Kafka 4.0을 사용해야 함) 프로세스가 호출됩니다. KRaft 마이그레이션 버전 3.5부터 공식적으로 지원됩니다. 좋은 소식: 마이그레이션이 발생합니다. 다운타임 없이 생산자와 소비자를 위한.
마이그레이션 단계
공식 프로세스는 6단계로 구분됩니다.
-
전제 조건 확인: Kafka 3.7로 업그레이드(ZooKeeper+KRaft 이중 쓰기를 지원하는 최신 버전),
모든 브로커가 가지고 있는지 확인하십시오
metadata.version정렬되었습니다. - KRaft 컨트롤러 배포: KRaft 컨트롤러 노드를 시작합니다(새 노드 3개 또는 기존 브로커 추가 역할). 컨트롤러는 마이그레이션 도구를 통해 ZooKeeper로부터 초기 메타데이터를 얻습니다.
- 이중 쓰기 모드: 브로커는 ZooKeeper와 KRaft 메타데이터 로그 모두에 메타데이터를 기록합니다. 이 단계에서는 시스템이 완전히 작동합니다.
- 마이그레이션 완료: 모든 브로커가 마이그레이션되고 ZooKeeper는 Kafka에 대해 읽기 전용이 됩니다. 생산자와 소비자는 어떠한 방해도 인식하지 못합니다.
- ZooKeeper 종료자: ZooKeeper에서 Kafka 메타데이터를 정리하는 종료자를 실행합니다.
- ZooKeeper 종료: ZooKeeper 앙상블을 폐기합니다. 완전 KRaft 클러스터.
# Step 1: Verifica metadata.version attuale del cluster
# (da eseguire con Kafka 3.7)
kafka-features.sh --bootstrap-server kafka1:9092 describe
# Output:
# Feature: metadata.version
# SupportedMinVersion: 3.0-IV1
# SupportedMaxVersion: 3.7-IV4
# FinalizedVersion: 3.7-IV4
# Step 2: Avvia i controller KRaft con la migration config speciale
# In server.properties dei controller KRaft:
process.roles=controller
zookeeper.connect=zk1:2181,zk2:2181,zk3:2181 # ancora necessario in fase di migrazione
controller.quorum.voters=10@kc1:9093,11@kc2:9093,12@kc3:9093
# Step 3: Avvia la migration (da eseguire una volta soli i controller KRaft sono up)
# Modifica server.properties di OGNI broker Kafka esistente:
# Aggiunge il parametro:
zookeeper.metadata.migration.enable=true
controller.quorum.voters=10@kc1:9093,11@kc2:9093,12@kc3:9093
# Riavvia i broker uno alla volta (rolling restart, zero downtime)
# I broker entrano in migration mode automaticamente
# Step 4: Monitora lo stato della migrazione
kafka-metadata-shell.sh \
--snapshot /var/lib/kafka/data/__cluster_metadata-0/00000000000000000000.snapshot
# Step 5: Finalizza (dopo che tutti i broker sono migrati)
kafka-features.sh --bootstrap-server kafka1:9092 upgrade \
--metadata 3.7-IV4 # o la versione target
# Step 6: Rimuovi zookeeper.connect dai server.properties e riavvia i broker
마이그레이션에 대한 중요 공지
- 쉽게 돌아가지 마: KRaft 마이그레이션이 완료되고 ZooKeeper가 제거되면, 롤백은 매우 복잡합니다. 먼저 프로덕션과 동일한 스테이징 환경으로 마이그레이션하세요.
- ACL 및 구성: ZooKeeper를 통해 관리되는 ACL 및 동적 구성이 마이그레이션됩니다. 메타데이터 로그에 자동으로 포함되지만 마이그레이션 후에는 존재하는지 확인하세요.
- 커넥터 Kafka 연결: Kafka 클러스터를 상태의 백엔드로 사용하는 커넥터 (group.id, 오프셋)은 변경 없이 계속 작동합니다.
- 미러메이커 2: 지역 복제에 MM2를 사용하는 경우 동일한 위치에서 원격 클러스터를 업데이트하세요. 버전 비호환성을 방지하기 위한 유지 관리 기간.
고급 구성을 갖춘 KRaft: 전용 컨트롤러
처리량이 높거나 많은 수의 파티션(>50,000)을 관리하는 클러스터의 경우 컨트롤러는 브로커(전용 컨트롤러)와 분리하는 것이 좋습니다. 이렇게 메타데이터 작업(주제 생성, 리더 선택, 구성 변경)은 경쟁하지 않습니다. 동일한 디스크에 파티션 로그 I/O가 있습니다.
# server.properties per un CONTROLLER DEDICATO (non gestisce partizioni utente)
node.id=10
process.roles=controller
controller.quorum.voters=10@kc1:9093,11@kc2:9093,12@kc3:9093
listeners=CONTROLLER://kc1:9093
listener.security.protocol.map=CONTROLLER:PLAINTEXT
controller.listener.names=CONTROLLER
log.dirs=/var/lib/kafka/metadata
# server.properties per un BROKER PURO (non è controller)
node.id=1
process.roles=broker
controller.quorum.voters=10@kc1:9093,11@kc2:9093,12@kc3:9093
listeners=KAFKA://kafka1:9092
advertised.listeners=KAFKA://kafka1:9092
listener.security.protocol.map=KAFKA:PLAINTEXT
inter.broker.listener.name=KAFKA
controller.listener.names=CONTROLLER
log.dirs=/var/lib/kafka/data
# Con questa configurazione:
# - 3 macchine controller dedicati (leggeri, poca RAM, poca CPU)
# - N broker puri (ottimizzati per I/O disco)
# - Nessuna competizione di risorse tra metadata ops e I/O partizioni
Confluent Cloud 및 Amazon MSK(버전 3.6부터 KRaft를 채택)와 같은 관리형 환경에서는 컨트롤러/브로커 분리는 자동으로 이루어지며 사용자에게 투명합니다.
KRaft의 운영상 이점
더 빠른 시작 및 복구
ZooKeeper를 사용하면 Kafka 브로커 컨트롤러가 다시 시작될 때 클러스터의 전체 상태를 읽어야 했습니다. 작동하기 전에 ZooKeeper에서. 100,000개 이상의 파티션이 있는 클러스터의 경우 이 작업에 시간이 걸릴 수 있습니다. 30~90초 컨트롤러를 사용할 수 없습니다.
KRaft를 사용하면 리더 컨트롤러가 메타데이터 로그를 이미 메모리와 로컬 디스크에 유지합니다. 장애 조치 일반적으로 컨트롤러에는 5초 미만, 대규모 클러스터의 경우에도 마찬가지입니다. 사례 연구 한 핀테크 회사(Confluent Engineering Blog, 2025)는 설정 시간이 40% 단축되었음을 기록합니다. KRaft로 마이그레이션한 후
메타데이터 확장성
ZooKeeper에는 성능에 관계없이 클러스터당 약 200,000개의 파티션이라는 실질적인 제한이 있었습니다. 메타데이터 작업의 성능이 크게 저하됨) KRaft는 메타데이터 로그를 정상적으로 처리합니다. Kafka는 압축을 통해 로그를 기록하고 다음과 같이 테스트되었습니다. 수백만 개의 파티션 클러스터당.
운영 단순성
ZooKeeper를 제거하는 것은 다음을 의미합니다.
- 두 대가 아닌 한 대의 시스템으로 모니터링
- 2번이 아닌 1번의 업그레이드 주기(주로 ZooKeeper와 Kafka에는 복잡한 버전 제약이 있음)
- Kubernetes에 더 쉽게 배포(StatefulSet 감소, PVC 감소)
- 더 쉬운 재해 복구(클러스터 상태는 Kafka와 ZooKeeper 간에 분산되지 않고 메타데이터 로그에 있음)
Strimzi를 사용한 Kubernetes의 KRaft
스트림지 Kafka 관리에 가장 널리 사용되는 Kubernetes 연산자입니다. 버전 0.38부터, Strimzi는 기본적으로 KRaft를 지원합니다.
# Kafka cluster KRaft con Strimzi Operator (Kubernetes)
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: my-cluster
namespace: kafka
annotations:
# Abilita KRaft mode (richiede Strimzi 0.38+)
strimzi.io/kraft: enabled
spec:
kafka:
version: 4.0.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9093
type: internal
tls: true
config:
# KRaft-specific
default.replication.factor: 3
min.insync.replicas: 2
offsets.topic.replication.factor: 3
transaction.state.log.replication.factor: 3
transaction.state.log.min.isr: 2
# Retention
log.retention.hours: 168
log.segment.bytes: 1073741824
storage:
type: persistent-claim
size: 100Gi
class: fast-ssd
# Controller separato (produzione: controller dedicati)
# Ometti questa sezione per controller combinati (default)
# entityOperator gestisce topic e utenti tramite CRD
entityOperator:
topicOperator: {}
userOperator: {}
# Creare un topic con Strimzi CRD (invece di kafka-topics.sh)
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaTopic
metadata:
name: ordini-effettuati
namespace: kafka
labels:
strimzi.io/cluster: my-cluster
spec:
partitions: 6
replicas: 3
config:
retention.ms: "604800000"
min.insync.replicas: "2"
compression.type: snappy
KRaft 클러스터 상태 확인
# Verificare chi è il controller leader attuale
kafka-metadata-quorum.sh \
--bootstrap-server kafka1:9092 \
describe --status
# Output:
# ClusterId: MkU3OEVBNTcwNTJENDM2Qk
# LeaderId: 1
# LeaderEpoch: 42
# HighWatermark: 156789
# MaxFollowerLag: 0
# MaxFollowerLagTimeMs: 12
# CurrentVoters: [{"nodeId":1,"logEndOffset":156789,"lag":0},
# {"nodeId":2,"logEndOffset":156789,"lag":0},
# {"nodeId":3,"logEndOffset":156789,"lag":0}]
# CurrentObservers: []
# Verificare i dettagli del quorum
kafka-metadata-quorum.sh \
--bootstrap-server kafka1:9092 \
describe --replication
# Leggere il metadata log (per debugging)
kafka-dump-log.sh \
--files /var/lib/kafka/data/__cluster_metadata-0/00000000000000000000.log \
--cluster-metadata
구성 차이점: ZooKeeper와 KRaft
ZooKeeper 클러스터에서 오는 경우 알아야 할 주요 구성 차이점은 다음과 같습니다.
| 구성 | ZooKeeper모드 | KRaft모드 |
|---|---|---|
| 클러스터 연결 | zookeeper.connect |
controller.quorum.voters |
| 노드 ID | broker.id |
node.id |
| 역할 | 항상 브로커 | process.roles |
| 리스너 컨트롤러 | 해당 없음 | controller.listener.names |
| 초기화 | 자동차(ZK 핸들) | kafka-storage.sh format |
| ACL 스토리지 | ZooKeeper znodes | 메타데이터 로그 |
KRaft의 메타데이터 버전 및 기능 플래그
KRaft를 통해 Kafka는 메타데이터.버전: 메타데이터 형식의 버전 클러스터에서. 이를 통해 가동 중지 시간 없이 한 번에 한 노드씩 클러스터를 롤링 업그레이드할 수 있습니다. 메타데이터 버전은 클러스터의 모든 브로커가 새 버전을 지원하는 경우에만 업데이트됩니다.
# Verificare la metadata.version corrente e le versioni supportate
kafka-features.sh \
--bootstrap-server kafka1:9092 \
describe
# Output tipico con Kafka 4.0:
# Feature: metadata.version
# SupportedMinVersion: 3.0-IV1
# SupportedMaxVersion: 4.0-IV3
# FinalizedVersion: 4.0-IV3
# Verificare tutti i feature flags disponibili
kafka-features.sh \
--bootstrap-server kafka1:9092 \
describe --all
# Aggiornare la metadata.version dopo un upgrade di cluster
# (eseguire DOPO che tutti i broker sono stati aggiornati alla nuova versione)
kafka-features.sh \
--bootstrap-server kafka1:9092 \
upgrade --metadata 4.0-IV3
버전 4.0-IV3 (Kafka 4.0 Incremental Version 3)은 릴리스에서 사용 가능한 최신 버전입니다.
Kafka 4.0 2025년 3월. 버전이 증가할 때마다 새로운 기능과 프로토콜 최적화가 가능해집니다.
KRaft 문제 해결: 일반적인 문제
클러스터가 시작되지 않음: "정족수에서 유권자를 찾을 수 없습니다."
이 오류는 컨트롤러 노드가 다른 쿼럼 투표자를 찾을 수 없음을 나타냅니다. 일반적인 원인:
-
잘못 구성된 Controller.quorum.voters: 형식이 올바른지 확인하세요.
(
nodeId@hostname:port) 그리고 호스트 이름은 모든 노드에서 확인할 수 있습니다. - 컨트롤러 리스너에 연결할 수 없습니다.: 방화벽이 허용하는지 확인하세요. 컨트롤러 노드 간 컨트롤러 리스너 포트(기본값: 9093)에서의 통신입니다.
-
클러스터 ID 불일치: 재부팅 한 경우
kafka-storage.sh format올바른 클러스터 ID를 사용하지 않고 노드 중 하나에서 노드가 클러스터에 참여하지 않습니다.
# Verificare il cluster ID su ogni nodo
cat /var/lib/kafka/data/meta.properties
# node.id=1
# version=1
# cluster.id=MkU3OEVBNTcwNTJENDM2Qk <-- deve essere identico su tutti i nodi
# Verificare che il controller leader sia eletto
kafka-metadata-quorum.sh \
--bootstrap-server kafka1:9092 \
describe --status | grep LeaderId
# Se LeaderId=-1, nessun leader è stato eletto (quorum non raggiunto)
# Controllare i log del broker per errori KRaft
grep -E "WARN|ERROR" /var/log/kafka/kafka.log | grep -i "kraft\|quorum\|controller"
브로커가 클러스터에 추가되지 않음
기존 KRaft 클러스터에 새 브로커를 추가하는 경우 브로커를 포맷해야 합니다. 기존 클러스터와 동일한 클러스터 ID를 사용합니다.
# Recupera il cluster ID dal cluster esistente
CLUSTER_ID=$(kafka-metadata-quorum.sh \
--bootstrap-server kafka1:9092 \
describe --status | grep ClusterId | awk '{print $2}')
echo "Cluster ID: $CLUSTER_ID"
# Formatta il nuovo broker con lo stesso cluster ID
kafka-storage.sh format \
--config /etc/kafka/server.properties \
--cluster-id "$CLUSTER_ID"
# Avvia il nuovo broker
kafka-server-start.sh /etc/kafka/server.properties
# Verifica che il nuovo broker sia visibile nel cluster
kafka-broker-api-versions.sh \
--bootstrap-server kafka1:9092 | grep "id:"
시리즈의 다음 단계
KRaft가 포함되어 있으면 Kafka 구성의 고급 측면을 다룰 준비가 된 것입니다.
-
제3조 - 고급 생산자 및 소비자: 세부 구성
acks,idempotent producer, 중복 없이 내구성을 보장하는 재시도 전략입니다. - 4조 - 정확히 1회 의미론: 원자 쓰기를 위한 Kafka 트랜잭션 KRaft 메타데이터 로그에 구현된 새로운 트랜잭션 코디네이터를 사용하여 여러 주제에 대해 설명합니다.
- 제 11조 - 생산 중인 카프카: KRaft 클러스터 크기 조정, 구성 컨트롤러 복제본, 재해 복구 및 메타데이터 로그 백업.
다른 시리즈와의 연계
- 고급 쿠버네티스: Strimzi 연산자를 사용하여 Kubernetes에 Kafka 배포, 지속적인 스토리지 관리 및 소비자 그룹 자동 크기 조정.
-
관찰 가능성: JMX 내보내기를 사용한 KRaft 쿼럼 모니터링, 중요한 측정항목
어떻게
kafka.controller:type=KafkaController,name=ActiveControllerCount그리고 리더 선출에 대해 경고합니다.







