카프카 서버 한 대가 브로커고, 브로커 여럿이 모인 것이 클러스터다. 브로커는 처음부터 클러스터의 일부로 작동하도록 설계되었다.
브로커와 컨트롤러
브로커가 하는 일은 단순하다. 프로듀서에게 메시지를 받아 오프셋을 할당하고 디스크 저장소에 쓰고, 컨슈머의 읽기 요청을 받아 저장된 메시지를 보내준다. 초당 수천 개의 파티션, 수백만 개의 메시지를 처리한다. 파티션 하나는 클러스터 안의 브로커 중 하나가 담당하고, 그 브로커를 파티션 리더라고 부른다.
클러스터에는 컨트롤러가 하나 있다. 작동 중인 브로커 중 하나가 자동으로 선정되어 파티션을 브로커에 할당하고 장애가 난 브로커를 모니터링한다.
무중단 확장
이 구조 덕분에 클러스터는 작동 중에도 전체 가용성에 영향을 주지 않으면서 확장된다. 여러 대로 구성된 클러스터는 개별 브로커의 장애를 처리하면서 계속 클라이언트 요청을 받고, 동시다발적인 장애를 견뎌야 하면 복제 팩터를 더 크게 잡는다.
상태를 바꾸는 작업과 읽는 작업
관리 작업은 두 갈래로 갈린다. 상태를 바꾸는 작업(create, delete, alter)은 컨트롤러가 수행하고, 상태를 읽기만 하는 작업(list, describe)은 아무 브로커에서나 처리된다. 후자는 클라이언트 입장에서 부하가 가장 적은 브로커로 전달된다. 어드민 작업에서 어디에 부하가 걸리는지 짐작할 때 쓰는 구분이다.
메타데이터 저장소
브로커의 메타데이터를 어디에 두느냐가 두 갈래다.
주키퍼
설정 정보 관리, 이름 부여, 분산 동기화, 그룹 서비스를 제공하는 중앙화된 서비스다. 카프카 클러스터의 메타데이터와 컨슈머 클라이언트 정보를 여기에 저장한다. 브로커는 zookeeper.connect에 호스트이름:포트/경로 형태로 위치를 잡는데, 뒤의 경로가 chroot라서 다른 카프카 클러스터와 앙상블을 공유해도 충돌하지 않는다.
주키퍼는 고가용성을 위해 앙상블(ensemble)이라는 클러스터 단위로 작동하고, 홀수 개의 서버를 권장한다. 요청에 응답하려면 앙상블 멤버(쿼럼)의 과반 이상이 살아 있어야 하기 때문이다.
크기는 다섯 대를 먼저 고려한다. 설정을 바꾸려면 한 대씩 정지하고 재시작해야 하는데, 두 대 이상의 정지를 못 견디면 정비 작업 자체가 위험해진다. 아홉 대 이상은 권장하지 않는다. 합의 프로토콜 특성상 성능이 떨어지기 시작한다. 클라이언트 연결이 너무 많아 다섯이나 일곱 대로 부하를 감당하기 어려우면 옵저버 노드를 추가해 읽기 전용 트래픽을 분산한다.
KRaft
외부 시스템 없이 카프카 자체가 메타데이터 합의를 처리하는 방식이다. 주키퍼 지원은 4.0에서 완전히 제거되었다.
주키퍼가 사라져도 메타데이터에 별도의 합의가 필요하다는 구조는 남는다. 쿼럼과 과반이라는 개념이 KRaft 컨트롤러 쪽으로 옮겨갔을 뿐이다.
참고
원본은 KRaft를 “Kafka Raft Metadata Model”의 약자로 적었으나 KRaft는 Kafka Raft의 축약이다. 주키퍼 지원 중단도 “최신 버전”이라고만 적었는데, KIP-500 로드맵에 따라 3.5에서 지원 중단이 예고되었고 4.0(2025년 3월)에서 주키퍼 모드가 제거되었다. 4.0부터는 KRaft가 유일한 실행 모드다. Apache Kafka 4.0 Release Announcement