KRaft
KRaft
이 페이지는 Zookeeper 없이 Kafka 자체가 메타데이터를 관리하는 KRaft 모드의 운영 방법을 다뤄요. 컨트롤러·브로커 역할 구성, 노드 프로비저닝, 동적 컨트롤러 쿼럼, 업그레이드, 디버깅 도구까지 실무에 꼭 필요한 내용이 담겨 있어요.
출처: 문서
본문
구성 (Configuration)
프로세스 역할 (Process Roles)
KRaft 모드에서 각 Kafka 서버는 process.roles 속성으로 컨트롤러, 브로커, 또는 둘 다로 구성할 수 있습니다. 이 속성은 다음 값을 가질 수 있습니다.
process.roles가broker로 설정되면 서버는 브로커로 동작.process.roles가controller로 설정되면 서버는 컨트롤러로 동작.process.roles가broker,controller로 설정되면 서버는 브로커와 컨트롤러 둘 다로 동작.
브로커와 컨트롤러 둘 다로 동작하는 Kafka 서버를 "combined" 서버라고 합니다. Combined 서버는 개발 환경 같은 소규모 사용 사례에서 운영하기가 더 간단합니다. 핵심 단점은 컨트롤러가 시스템의 나머지 부분에서 덜 격리된다는 것입니다. 예를 들어 combined 모드에서는 브로커와 별도로 컨트롤러를 롤링하거나 확장하는 것이 불가능합니다. Combined 모드는 중요 배포 환경에서는 권장되지 않습니다.
컨트롤러 (Controllers)
KRaft 모드에서 특정 Kafka 서버가 컨트롤러로 선택됩니다. 컨트롤러로 선택된 서버들은 메타데이터 쿼럼(metadata quorum)에 참여합니다. 각 컨트롤러는 현재 활성 컨트롤러의 활성 또는 핫 대기(hot standby)입니다.
Kafka 관리자는 비용과 시스템이 가용성 영향 없이 견뎌야 하는 동시 장애 수 같은 요소에 따라 이 역할에 보통 3개 또는 5개의 서버를 선택합니다. 가용성을 유지하려면 컨트롤러 과반수(majority)가 살아 있어야 합니다. 컨트롤러 3개로 클러스터는 1개의 컨트롤러 장애를 견딜 수 있고, 5개로 2개의 컨트롤러 장애를 견딜 수 있습니다.
Kafka 클러스터의 모든 서버는 controller.quorum.bootstrap.servers 속성을 사용해 활성 컨트롤러를 발견합니다. 모든 컨트롤러가 이 속성에 열거되어야 합니다. 각 컨트롤러는 호스트와 포트 정보로 식별됩니다. 예:
controller.quorum.bootstrap.servers=host1:port1,host2:port2,host3:port3
Kafka 클러스터에 controller1, controller2, controller3이라는 3개의 컨트롤러가 있다면 controller1은 다음 구성을 가질 수 있습니다.
process.roles=controller
node.id=1
listeners=CONTROLLER://controller1.example.com:9093
controller.quorum.bootstrap.servers=controller1.example.com:9093,controller2.example.com:9093,controller3.example.com:9093
controller.listener.names=CONTROLLER
모든 브로커와 컨트롤러는 controller.quorum.bootstrap.servers 속성을 설정해야 합니다.
업그레이드 (Upgrade)
Apache Kafka 4.1은 정적 컨트롤러 구성에서 동적 컨트롤러 구성으로 클러스터를 업그레이드하는 것을 지원했습니다. 동적 컨트롤러 구성은 사용자가 클러스터에 컨트롤러를 추가하고 제거할 수 있게 해줍니다. 자세한 내용은 컨트롤러 멤버십 변경 섹션을 참고하세요.
이 기능 업그레이드는 KRaft 기능 버전을 업그레이드하고 노드 구성을 업데이트함으로써 수행됩니다.
KRaft 버전 설명 (Describe KRaft Version)
동적 컨트롤러 클러스터는 kraft.version=1 또는 release-version 4.1에서 추가되었습니다. 클러스터가 어떤 kraft 기능 버전을 사용 중인지 확인하려면 다음 CLI 명령을 실행할 수 있습니다.
$ bin/kafka-features.sh --bootstrap-controller localhost:9093 describe
...
Feature: kraft.version SupportedMinVersion: 0 SupportedMaxVersion: 1 FinalizedVersionLevel: 0 Epoch: 7
Feature: metadata.version SupportedMinVersion: 3.3-IV3 SupportedMaxVersion: 4.0-IV3 FinalizedVersionLevel: 4.0-IV3 Epoch: 7
Feature: kraft.version의 FinalizedVersionLevel이 0이라면, 동적 컨트롤러 클러스터를 지원하려면 버전을 최소 1로 업그레이드해야 합니다.
KRaft 버전 업그레이드 (Upgrade KRaft Version)
동적 컨트롤러 클러스터를 지원하도록 KRaft 기능 버전은 kafka-feature CLI 명령으로 업그레이드할 수 있습니다. 모든 기능 버전을 최신 버전으로 업그레이드하려면:
$ bin/kafka-features.sh --bootstrap-server localhost:9092 upgrade --release-version 4.1
KRaft 기능 버전만 업그레이드하려면:
$ bin/kafka-features.sh --bootstrap-server localhost:9092 upgrade --feature kraft.version=1
KRaft 구성 업데이트 (Update KRaft Config)
KRaft 버전 1은 controller.quorum.voters 속성을 폐기하고 controller.quorum.bootstrap.servers 속성을 추가했습니다. KRaft 버전이 성공적으로 최소 1로 업그레이드되었는지 확인한 후, 클러스터의 모든 노드(컨트롤러와 브로커)에서 controller.quorum.voters 속성을 제거하고 controller.quorum.bootstrap.servers를 추가하세요.
process.roles=...
node.id=...
controller.quorum.bootstrap.servers=controller1.example.com:9093,controller2.example.com:9093,controller3.example.com:9093
controller.listener.names=CONTROLLER
노드 프로비저닝 (Provisioning Nodes)
bin/kafka-storage.sh random-uuid 명령은 새 클러스터의 클러스터 ID를 생성하는 데 사용할 수 있습니다. 이 클러스터 ID는 bin/kafka-storage.sh format 명령으로 클러스터의 각 서버를 포맷할 때 사용해야 합니다.
이것은 Kafka가 과거에 운영해온 방식과 다릅니다. 이전에는 Kafka가 빈 저장 디렉터리를 자동으로 포맷하고 새 클러스터 ID도 자동으로 생성했습니다. 변경된 이유 중 하나는 자동 포맷이 때때로 오류 조건을 가릴 수 있기 때문입니다. 이는 특히 컨트롤러와 브로커 서버가 유지하는 메타데이터 로그에서 중요합니다. 컨트롤러 과반수가 빈 로그 디렉터리로 시작할 수 있다면 커밋된 데이터가 없는 상태로 리더가 선출될 수 있습니다.
단독 컨트롤러 부트스트랩 (Bootstrap a Standalone Controller)
새 KRaft 컨트롤러 클러스터를 만드는 권장 방법은 하나의 투표자(voter)로 부트스트랩하고 나머지 컨트롤러를 동적으로 추가하는 것입니다. 첫 컨트롤러 부트스트랩은 다음 CLI 명령으로 할 수 있습니다.
$ bin/kafka-storage.sh format --cluster-id <CLUSTER_ID> --standalone --config config/controller.properties
이 명령은 1) metadata.log.dir에 랜덤 생성된 directory.id와 함께 meta.properties 파일을 만들고, 2) 이 Kafka 노드를 쿼럼의 유일한 투표자로 만드는 데 필요한 제어 레코드(KRaftVersionRecord와 VotersRecord)가 있는 00000000000000000000-0000000000.checkpoint에 스냅샷을 만듭니다.
여러 컨트롤러로 부트스트랩 (Bootstrap with Multiple Controllers)
KRaft 클러스터 메타데이터 파티션은 하나 이상의 투표자로도 부트스트랩할 수 있습니다. 이는 –initial-controllers 플래그를 사용해 할 수 있습니다.
CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
CONTROLLER_0_UUID="$(bin/kafka-storage.sh random-uuid)"
CONTROLLER_1_UUID="$(bin/kafka-storage.sh random-uuid)"
CONTROLLER_2_UUID="$(bin/kafka-storage.sh random-uuid)"
# In each controller execute
bin/kafka-storage.sh format --cluster-id ${CLUSTER_ID} \
--initial-controllers "0@controller-0:1234:${CONTROLLER_0_UUID},1@controller-1:1234:${CONTROLLER_1_UUID},2@controller-2:1234:${CONTROLLER_2_UUID}" \
--config config/controller.properties
이 명령은 standalone 버전과 유사하지만, 00000000000000000000-0000000000.checkpoint의 스냅샷이 대신 –initial-controllers에 지정된 모든 컨트롤러에 대한 정보를 포함하는 VotersRecord를 담습니다. 이 플래그의 값이 같은 클러스터 ID를 가진 모든 컨트롤러에서 동일해야 하는 것이 중요합니다. 복제본 설명 0@controller-0:1234:3Db5QLSqSZieL3rJBUUegA에서 0은 복제본 ID, 3Db5QLSqSZieL3rJBUUegA는 복제본 디렉터리 ID, controller-0은 복제본의 호스트, 1234는 복제본의 포트입니다.
브로커와 새 컨트롤러 포맷 (Formatting Brokers and New Controllers)
기존 Kafka 클러스터에 추가하려는 새 브로커와 컨트롤러 노드를 프로비저닝할 때는 –no-initial-controllers 플래그와 함께 kafka-storage.sh format 명령을 사용하세요.
$ bin/kafka-storage.sh format --cluster-id <CLUSTER_ID> --config config/server.properties --no-initial-controllers
컨트롤러 멤버십 변경 (Controller membership changes)
정적 vs 동적 KRaft 쿼럼 (Static versus Dynamic KRaft Quorums)
KRaft 실행에는 두 가지 방식이 있습니다. KIP-853의 동적 컨트롤러 쿼럼(dynamic controller quorums) 또는 정적 컨트롤러 쿼럼(static controller quorums)을 사용하는 옛 방식입니다.
동적 쿼럼을 사용할 때는 controller.quorum.voters를 설정해서는 안 되며 대신 controller.quorum.bootstrap.servers를 설정합니다. 이 구성 키는 모든 컨트롤러를 담을 필요는 없지만, 모든 서버가 쿼럼을 찾을 수 있도록 가능한 한 많이 담아야 합니다. 즉, 그 기능은 Kafka 클라이언트가 사용하는 bootstrap.servers 구성과 매우 비슷합니다.
정적 쿼럼을 사용할 때는 각 브로커와 컨트롤러의 구성 파일이 controller.quorum.voters에 모든 컨트롤러의 ID, 호스트명, 포트를 지정해야 합니다.
정적 또는 동적 쿼럼을 사용 중인지 확실하지 않다면 다음과 같이 실행해 확인할 수 있습니다.
$ bin/kafka-features.sh --bootstrap-controller localhost:9093 describe
kraft.version 필드가 레벨 0이거나 없으면 정적 쿼럼을 사용 중인 것입니다. 1 이상이면 동적 쿼럼을 사용 중입니다. 예를 들어 다음은 정적 쿼럼의 예입니다.
Feature: kraft.version SupportedMinVersion: 0 SupportedMaxVersion: 1 FinalizedVersionLevel: 0 Epoch: 5
Feature: metadata.version SupportedMinVersion: 3.3-IV3 SupportedMaxVersion: 3.9-IV0 FinalizedVersionLevel: 3.9-IV0 Epoch: 5
다음은 정적 쿼럼의 또 다른 예입니다.
Feature: metadata.version SupportedMinVersion: 3.3-IV3 SupportedMaxVersion: 3.8-IV0 FinalizedVersionLevel: 3.8-IV0 Epoch: 5
다음은 동적 쿼럼의 예입니다.
Feature: kraft.version SupportedMinVersion: 0 SupportedMaxVersion: 1 FinalizedVersionLevel: 1 Epoch: 5
Feature: metadata.version SupportedMinVersion: 3.3-IV3 SupportedMaxVersion: 3.9-IV0 FinalizedVersionLevel: 3.9-IV0 Epoch: 5
쿼럼의 정적/동적 특성은 포맷 시점에 결정됩니다. 구체적으로 controller.quorum.voters가 없고 –standalone, –initial-controllers, 또는 –no-initial-controllers 중 하나가 설정되면 쿼럼이 동적으로 포맷됩니다. 이 문서의 앞부분 지침을 따랐다면 동적 쿼럼을 얻게 됩니다.
참고: 정적 투표자 집합에서 동적 투표자 집합으로 마이그레이션하려면 업그레이드 섹션을 참고하세요.
새 컨트롤러 추가 (Add New Controller)
동적 컨트롤러 클러스터가 이미 존재한다면, kafka-storage.sh 도구로 새 컨트롤러를 프로비저닝하고 컨트롤러를 시작함으로써 확장할 수 있습니다. 컨트롤러를 시작한 후 bin/kafka-metadata-quorum.sh describe --replication 명령으로 새 컨트롤러로의 복제를 모니터링할 수 있습니다. 새 컨트롤러가 활성 컨트롤러를 따라잡으면 bin/kafka-metadata-quorum.sh add-controller 명령으로 클러스터에 추가할 수 있습니다. 브로커 엔드포인트를 사용할 때는 –bootstrap-server 플래그를 사용합니다.
$ bin/kafka-metadata-quorum.sh --command-config config/controller.properties --bootstrap-server localhost:9092 add-controller
컨트롤러 엔드포인트를 사용할 때는 –bootstrap-controller 플래그를 사용합니다.
$ bin/kafka-metadata-quorum.sh --command-config config/controller.properties --bootstrap-controller localhost:9093 add-controller
Admin Client에 전달해야 하는 인증 구성 같은 구성이 있다면 "controller.properties"에도 포함하는 것이 좋다는 점에 유의하세요.
컨트롤러 제거 (Remove Controller)
동적 컨트롤러 클러스터가 이미 존재한다면 bin/kafka-metadata-quorum.sh remove-controller 명령으로 축소할 수 있습니다. 컨트롤러를 종료하기 전에 remove-controller 명령을 사용해 먼저 쿼럼에서 제거하세요. 브로커 엔드포인트를 사용할 때는 –bootstrap-server 플래그를 사용합니다.
$ bin/kafka-metadata-quorum.sh --bootstrap-server localhost:9092 remove-controller --controller-id <id> --controller-directory-id <directory-id>
컨트롤러 엔드포인트를 사용할 때는 –bootstrap-controller 플래그를 사용합니다.
$ bin/kafka-metadata-quorum.sh --bootstrap-controller localhost:9093 remove-controller --controller-id <id> --controller-directory-id <directory-id>
디버깅 (Debugging)
메타데이터 쿼럼 도구 (Metadata Quorum Tool)
kafka-metadata-quorum.sh 도구는 클러스터 메타데이터 파티션의 런타임 상태를 설명하는 데 사용할 수 있습니다. 예를 들어 다음 명령은 메타데이터 쿼럼의 요약을 표시합니다.
$ bin/kafka-metadata-quorum.sh --bootstrap-server localhost:9092 describe --status
ClusterId: fMCL8kv1SWm87L_Md-I2hg
LeaderId: 3002
LeaderEpoch: 2
HighWatermark: 10
MaxFollowerLag: 0
MaxFollowerLagTimeMs: -1
CurrentVoters: [{"id": 3000, "directoryId": "ILZ5MPTeRWakmJu99uBJCA", "endpoints": ["CONTROLLER://localhost:9093"]},
{"id": 3001, "directoryId": "b-DwmhtOheTqZzPoh52kfA", "endpoints": ["CONTROLLER://localhost:9094"]},
{"id": 3002, "directoryId": "g42deArWBTRM5A1yuVpMCg", "endpoints": ["CONTROLLER://localhost:9095"]}]
CurrentObservers: [{"id": 0, "directoryId": "3Db5QLSqSZieL3rJBUUegA"},
{"id": 1, "directoryId": "UegA3Db5QLSqSZieL3rJBU"},
{"id": 2, "directoryId": "L3rJBUUegA3Db5QLSqSZie"}]
Dump Log 도구 (Dump Log Tool)
kafka-dump-log.sh 도구는 클러스터 메타데이터 디렉터리의 로그 세그먼트와 스냅샷을 디버깅하는 데 사용할 수 있습니다. 이 도구는 제공된 파일을 스캔하고 메타데이터 레코드를 디코딩합니다. 예를 들어 다음 명령은 첫 번째 로그 세그먼트의 레코드를 디코딩해 출력합니다.
$ bin/kafka-dump-log.sh --cluster-metadata-decoder --files metadata_log_dir/__cluster_metadata-0/00000000000000000000.log
다음 명령은 클러스터 메타데이터 스냅샷의 레코드를 디코딩해 출력합니다.
$ bin/kafka-dump-log.sh --cluster-metadata-decoder --files metadata_log_dir/__cluster_metadata-0/00000000000000000100-0000000001.checkpoint
메타데이터 셸 (Metadata Shell)
kafka-metadata-shell.sh 도구는 클러스터 메타데이터 파티션의 상태를 대화형으로 검사하는 데 사용할 수 있습니다.
$ bin/kafka-metadata-shell.sh --snapshot metadata_log_dir/__cluster_metadata-0/00000000000000007228-0000000001.checkpoint
>> ls /
brokers local metadataQuorum topicIds topics
>> ls /topics
foo
>> cat /topics/foo/0/data
{
"partitionId" : 0,
"topicId" : "5zoAlv-xEh9xRANKXt1Lbg",
"replicas" : [ 1 ],
"isr" : [ 1 ],
"removingReplicas" : null,
"addingReplicas" : null,
"leader" : 1,
"leaderEpoch" : 0,
"partitionEpoch" : 0
}
>> exit
참고: 00000000000000000000-0000000000.checkpoint에는 클러스터 메타데이터가 포함되어 있지 않습니다. kafka-metadata-shell.sh 도구로 메타데이터를 검사할 때는 유효한 스냅샷 파일을 사용하세요.
배포 고려 사항 (Deploying Considerations)
- Kafka 서버의
process.roles는 broker 또는 controller 중 하나로 설정해야 하며 둘 다로 해서는 안 됩니다. Combined 모드는 개발 환경에서 사용할 수 있지만 중요 배포 환경에서는 피해야 합니다. - 중복성을 위해 Kafka 클러스터는 비용과 시스템이 가용성 영향 없이 견뎌야 하는 동시 장애 수 같은 요소에 따라 3개 이상의 컨트롤러를 사용해야 합니다. KRaft 컨트롤러 클러스터가 N개의 동시 장애를 견디려면 컨트롤러 클러스터가 2N + 1개의 컨트롤러를 포함해야 합니다.
- Kafka 컨트롤러는 클러스터의 모든 메타데이터를 메모리와 디스크에 저장합니다. 일반적인 Kafka 클러스터에는 메타데이터 로그 디렉터리에 5GB의 메인 메모리와 5GB의 디스크 공간이면 충분하다고 우리는 믿습니다.
ZooKeeper에서 KRaft로의 마이그레이션 (ZooKeeper to KRaft Migration)
ZooKeeper에서 KRaft로 마이그레이션하려면 브리지 릴리스(bridge release)를 사용해야 합니다. 마지막 브리지 릴리스는 Kafka 3.9입니다. 3.9 문서의 ZooKeeper to KRaft Migration 단계를 참고하세요.
더 알아보기 (Learn more)
process.roles와controller.quorum.bootstrap.servers가 KRaft 운영 구성의 핵심이에요.- 동적 쿼럼을 사용하면 컨트롤러를 동적으로 추가·제거할 수 있어요.
kafka-metadata-quorum.sh,kafka-dump-log.sh,kafka-metadata-shell.sh가 강력한 디버깅 도구예요.