KRaft
카프카 클러스터를 구성 및 사용하게 되면(분산 애플리케이션 환경), 클러스터 환경 관리를 위한 코디네이터(애플리케이션)가 추가로 필요하기 마련이다. 이러한 코디네이터로 아파치 주키퍼가 많이 사용되고 있으며, 카프카에서도 주키퍼와 같이 사용하는 형태로 개발되어 왔다.
주키퍼는 하둡의 서브 프로젝트 중 하나로 출발해서 2011년 아파치의 탑 레벨 프로젝트로 승격이 되며, 여러 애플리케이션과 함께 사용되는 대표적인 분산 시스템 코디네이터 애플리케이션이다. 카프카 클러스터에서 주키퍼의 사용 또는 역할로는 주키퍼의 지노드(znode)를 이용해 카프카의 메타데이터(metadata) 관리, 브로커 상태 관리(노드관리), 토픽 관리, 컨트롤러 관리 등의 역할을 하고 있다.
다만 주키퍼를 통한 카프카 외부에서 메타데이터 관리 하다보니 데이터 중복 또는 브로커의 메타데이터와 주키퍼의 메타데이터의 불일치, 시스템 복잡성 증가, 서버나 시스템이 추가로 더 필요하거나 더 많은 자바 프로세스 실행 필요와 같은, 더 많은 자원의 소모 등의 문제점이 있다. 그리고 컨플루언트의 블로그에서는 다음과 같이 말하고 있다.
Actually, the problem is not with ZooKeeper itself but with the concept of external metadata management.
(사실 문제는 ZooKeeper 자체가 아니라 외부 메타데이터 관리 개념에 있습니다.)
카프카 자체가 아닌 외부에서 메타데이터를 관리하기 때문에 카프카 입장에서 주키퍼 사용 시 제약사항이나 한계성 등을 느끼게 되며, 이로 인해 kafka의 확장성에 제한이 되는 부분이 있다고 판단했다.
주키퍼 사용 시 이슈가 되는 부분들
1. 성능적인 부분
주키퍼를 사용하면서 여러 가지 불편, 제한적인 상황이 있었겠지만 카프카에서 새로운 방식의 메커니즘 도입을 결정하는데, 아마도 성능적인 이슈가 가장 큰 영향을 끼치지 않았나 싶다.
브로커는 모든 모든 토픽과 파티션에 대한 메타데이터를 주키퍼에서 읽어야 하며, 메타데이터의 업데이터는 주키퍼에서 동기방식으로 일어나고, 브로커에는 비동기방식으로 전달되었다. 이 과정에서 메타데이터의 불일치가 발생할 수도 있으며, 컨트롤러 재시작 시 모든 메타데이터를 주키퍼로부터 읽어야 하는 것도 부담이었다. 특히 토픽과 파티션이 많은 대규모 카프카 클러스터에서는 오랜 시간이 걸리는 등 병목현상이 발생할 수 있다.
2. 관리적인 부분
주키퍼와 카프카는 완전히 서로 다른 애플리케이션으로, 서로 다른 구성 파일, 환경, 서비스 데몬을 가지고 있다.
결국 관리자는 동시에 서로 다른 애플리케이션을 운영해야 한다.
동시에 두 가지 애플리케이션을 운영한다는 것은 관리자에게 큰 부담이 된다.
예를 들어, 주키퍼의 릴리스 노트 확인, 버전 업그레이드, 구성 파일 변경과 동시에 카프카의 릴리스 노트 확인, 버전 업그레이드, 구성 파일 변경을 해야 한다.
3. 모니터링 등
모든 서비스는 모니터링이 필수이며, 주키퍼와 카프카 둘 다 모니터링을 해야 한다.
두 애플리케이션은 서로 다른 애플리케이션이므로, 모니터링을 적용하는 방법과 각 애플리케이션에서 보여주는 주요 메트릭도 다르다.
또한 모니터링에 필요한 필수 메트릭을 이해하고 모니터링하는 방법까지 완전히 다르다.
그 외에도 각 애플리케이션에서 빈번하게 발생하는 이슈 또는 장애 상황에 개별적으로 대처해야 하며,
두 애플리케이션 간 통신 이슈라도 발생한다면, 매우 곤혹스러울 것이다.
KRaft 모드의 도입 배경과 목적
그래서 이러한 여러가지 문제와 고민에 의해서 2019년에 이러한 종속성을 깨고 새로운 메타데이터 관리를 Kafka 자체에 도입할 계획을 만들게 되었다.
새롭게 메타데이터 관리를 위해서 만들어진 것이 KRaft 모드이다.
KRaft 모드는 이전 컨트롤러를 대체하고 Raft 합의 프로토콜의 이벤트 기반 변형을 사용하는 Kafka의 새로운 쿼럼 컨트롤러 서비스를 사용한다.
- Zookeeper 의존성 제거: 기존 Kafka 아키텍처에서 Zookeeper는 브로커 관리, 토픽 메타데이터 관리 등 중요한 역할을 수행했다. 하지만 Zookeeper에 대한 의존성은 Kafka 클러스터의 운영 복잡성을 증가시켰고, 성능 병목 현상을 일으킬 수 있었다.
- 운영 단순화: Zookeeper를 제거함으로써 Kafka 클러스터의 설정, 관리, 모니터링이 간소화된다. 이는 전반적인 운영 비용을 줄이고, 시스템의 안정성을 향상시킬 수 있다.
- 성능 개선: Kafka 자체에서 메타데이터를 관리함으로써 성능이 개선될 수 있다. 특히 메타데이터 읽기/쓰기 작업에서 이점을 볼 수 있다.
Raft 프로토콜이란?
Raft는 분산 시스템에서 높은 가용성을 보장하면서 일관된 상태를 유지하기 위해 설계된 합의 알고리즘이다.
Raft는 분산된 노드 간에 안정적인 리더 선출과 로그 복제를 통해 시스템의 일관성을 유지한다.
이는 분산 시스템에서 매우 중요한 문제 중 하나로, 모든 노드가 동일한 순서로 동일한 결정을 내릴 수 있도록 보장한다.
주키퍼 모드 vs KRaft 모드
1. 주키퍼 모드
주키퍼 모드는 주키퍼 앙상블(Ensemble)과 카프카 클러스터가 존재하며, 카프카 클러스터 중 하나의 브로커가 컨트롤러 역할을 하게 된다.
컨트롤러는 파티션의 리더를 선출하는 역할을 하며, 리더 선출 정보를 브로커에게 전파하고 주키퍼에 리더 정보를 기록하는 역할을 한다. 컨트롤러의 선출 작업은 주키퍼를 통해 이루어지는데, 주키퍼의 임시노드를 통해 이루어진다.
임시노드에 가장 먼저 연결에 성공한 브로커가 컨트롤러가 되고, 다른 브로커들은 해당 임시노드에 이미 컨트롤러가 있다는 사실을 통해 카프카 클러스터 내 컨트롤러가 있다는 것을 인식하게 된다. 이를 통해 한 번에 하나의 컨트롤러만 클러스터에 있도록 보장할 수 있다.
2. KRaft 모드
그림에서 보는 바와 같이 KRaft 모드에서는 주키퍼가 사라진 것을 알 수 있다.
KRaft 모드는 주키퍼와의 의존성을 제거하고, 카프카 단일 애플리케이션 내에서 메타데이터 관리 기능을 수행하는 독립적인 구조가 되는 것이다. 주키퍼 모드에서 1개였던 컨트롤러가 3개로 늘어나고, 이들 중 하나의 컨트롤러가 액티브(그림에서 노란색 컨트롤러) 컨트롤러이면서 리더 역할을 담당한다.
리더 역할을 하는 컨트롤러가 write 하는 역할도 하게 된다.
또한 주키퍼 노드에서는 메타 데이터 관리를 주키퍼가 했다면, 이제는 카프카 내부의 별도 토픽을 이용하여 메타 데이터를 관리한다.
액티브인 컨트롤러가 장애 또는 종료되는 경우, 내부에서는 새로운 합의 알고리즘을 통해 새로운 리더를 선출하게 된다.
리더를 선출하는 과정을 간략히 설명드리자면, 후보자들은 적합한 리더를 투표하게 되고 후보자 중 충분한 표를 얻으면, 해당 컨트롤러가 새로운 리더가 된다.
KRaft 구성 방식
KRaft모드는 Zookeeper와 마찬가지로 여러 구성방식이 존재하다.
1. 별도의 Controller를 사용하여 구축하기
위와 같이 KRaft를 위한 컨트롤러 노드를 별도로 배치하여 높은 가용성과 안정성을 확보하는데 초점을 둘 수 있다.
이 방식으로 만약 브로커가 중단되더라도 KRaft는 장애 전파 없이 정상적인 동작을 보장할 수 있다.
클러스터의 관리 효율성과 시스템 전체의 안정성을 더 우선시해야한다면 이 방식을 고려할만하다.
2. KRaft와 Broker를 통합하기
위와 같이 컨트롤러와 브로커를 통합하여 사용할 수도 있다.
서버의 리소스가 한정적인 경우에는 이러한 방식으로 구축할 수 있지만 분리하여 사용하는 방식에 비해 안정성이 떨어지므로 권장되는 구성은 아니다. 라이브 환경이 아닌 개발환경에서는 이 구성이 적합할 수 있다.
쿼럼 컨트롤러
Kafka의 새로운 쿼럼 컨트롤러의 이점
- Kafka 클러스터는 새로운 메타데이터 관리로 향상된 컨트롤 플레인 성능을 통해 수백만 개의 파티션으로 확장할 수 있다.
- 안정성을 개선하고, 소프트웨어를 간소화하며, Kafka를 보다 쉽게 모니터링, 관리 및 지원할 수 있습니다.
- Kafka가 전체 시스템에 대한 단일 보안 모델을 가질 수 있도록 한다.
- Kafka를 시작하기 위한 간단한 단일 프로세스 방법 제공
- 컨트롤러 장애 조치(failover)를 거의 즉각적으로 만듭니다.
작동 원리
쿼럼 컨트롤러는 새로운 KRaft 프로토콜을 사용하여 메타데이터가 쿼럼 전체에 정확하게 복제되도록 한다.
쿼럼 컨트롤러는 이벤트 기반 저장소 모델을 사용하여 상태를 저장하며, 이를 통해 내부 상태 시스템을 항상 정확하게 다시 만들 수 있다. 이 상태를 저장하는 데 사용되는 이벤트 로그(메타데이터 항목이라고도 함)는 로그가 무한정 증가할 수 없도록 스냅숏으로 주기적으로 요약된다.
쿼럼 내의 다른 컨트롤러는 활성 컨트롤러가 만들고 로그에 저장하는 이벤트에 응답하여 활성 컨트롤러를 따릅니다. 따라서 예를 들어 파티셔닝 이벤트로 인해 한 노드가 일시 중지된 경우 다시 조인할 때 로그에 액세스 하여 놓친 이벤트를 빠르게 따라잡을 수 있다. 이렇게 하면 사용 불가 기간이 크게 줄어들어 최악의 경우 시스템 복구 시간이 향상된다.
KRaft 프로토콜의 이벤트 구동 특성은 ZooKeeper 기반 컨트롤러와 달리 쿼럼 컨트롤러가 활성화되기 전에 ZooKeeper에서 상태를 로드할 필요가 없음을 의미한다.
리더십이 변경되면 새 활성 제어기에는 이미 메모리에 커밋된 모든 메타데이터 레코드가 있습니다.
또한 KRaft 프로토콜에 사용된 것과 동일한 이벤트 기반 메커니즘이 클러스터 전체에서 메타데이터를 추적하는 데 사용된다.
이전에 RPC로 처리 되던 작업은 이제 이벤트 기반이 될 뿐만 아니라 실제 로그를 통신에 사용하는 이점이 있다.
KRaft의 성능
KRaft의 주요 성능 개선 중 하나는 파티션 리더 선출의 최적화이다.
앞에서 잠깐 언급했지만, 컨트롤러의 주요 역할은 파티션의 리더를 선출하는 것이다.
소수의 파티션에 대한 리더 선출 작업은 카프카 또는 카프카를 사용하는 클라이언트들에게 별다른 영향이 없겠으나, 대량의 파티션에 대한 리더 선출 작업은 다소 시간이 소요되며, 이러한 시간은 대량의 데이터 파이프라인의 역할을 하는 카프카와 클라이언트들에게 매우 크리티컬 한 요소일 수 있다.
따라서 이러한 지연 시간을 방지하고자 주키퍼 모드의 경우 카프카 클러스터 전체의 파티션 리미트는 약 200,000개 정도였으나, 리더 선출 과정을 개선한 KRaft 모드에서는 훨씬 더 많은 파티션 생성이 가능하다.
컨플루언트에서 공개한 KRaft 모드와 주키퍼 모드 간의 속도를 비교한 그림을 살펴보면, 복구 소요시간에서 엄청난 차이를 나타내고 있음을 알 수 있다. 이렇게 속도차이가 나는 이유는 KRaft모드에서의 컨트롤러는 메모리 내에 메타데이터 캐시를 유지하고 있으며, 주키퍼와의 의존성도 제거해 내부적으로 메타데이터의 동기화와 관리과정을 효율적으로 개선했기 때문이다.
또한 액티브 컨트롤러 장애 시 최신 메타데이터가 메모리에 유지되고 있으므로, 메타데이터 복제하는 시간도 줄어들어 보다 효율적인 컨트롤러 리더 선출 작업이 일어난다.
KRaft 서버 권장 사양
KRaft가 카프카와 같이 많은 데이터를 처리하지 않으므로 권장 사양은 생각보다 높지 않다.
- CPU: CPU를 공유하는 경우 Dedicated CPU
- MEM: 최소 4GB
- DISK: 최소 SSD 64GB
- JVM: 최소 1GB
참고
https://hoing.io/archives/4029
https://devocean.sk.com/blog/techBoardDetail.do?ID=165711&boardType=techBlog
https://devocean.sk.com/blog/techBoardDetail.do?ID=165737&boardType=techBlog
'Kafka' 카테고리의 다른 글
Kafka 기본 개념 (0) | 2024.07.12 |
---|---|
kafka가 왜 필요할까? (0) | 2024.07.07 |