[Kafka] 4. Broker
1. Kafka Broker
브로커는 Apache Kafka 생태계의 핵심 연산 노드 또는 서버입니다.
브로커는 메시지를 변경 불가능한 순서대로 저장하는 토픽 파티션(로그 파일)을 포함하고 있습니다.
프로듀서(생산자)는 메시지를 Kafka 브로커로 보내고, 브로커는 이 데이터를 여러 파티션에 걸쳐 저장합니다.
컨슈머(소비자)는 자신이 구독한 토픽에서 데이터를 가져오기 위해 브로커에 연결합니다.
Kafka 브로커는 시스템 장애가 발생하더라도 소비자에게 데이터를 신뢰성 있게 제공하는 것을 보장합니다.
2. Core Functions of Kafka Brokers
2.1. Message Management
프로듀서가 토픽에 메시지를 발행하면, 브로커는 프로듀서가 지정한 키(키를 기준으로 파티션이 결정됨)에 따라 또는 키가 지정되지 않은 경우 라운드 로빈 방식으로 토픽 내 어느 파티션에 메시지를 저장할지 결정합니다.
컨슈머들은 일반적으로 그룹을 이루어 토픽 파티션으로부터 레코드를 읽습니다.
그룹 내의 각 컨슈머는 토픽의 독립된 파티션을 읽으며, Kafka 브로커는 어떤 컨슈머가 어떤 파티션을 읽고 있는지를 추적합니다.
이러한 조정 과정을 통해 부하를 효율적으로 분산시키고, 그룹의 소비 정책에 따라 각 메시지가 그룹 내 단 하나의 컨슈머에게만 전달되도록 보장합니다.
Kafka 브로커는 또한 각 파티션의 로그 내 위치를 나타내는 오프셋을 추적합니다. 오프셋을 추적함으로써 컨슈머는 장애 발생이나 그룹 내 리밸런싱이 일어난 경우에도 마지막으로 읽은 위치부터 다시 소비를 이어갈 수 있게 됩니다.
2.2. Replication
여러 브로커는 함께 모여 클러스터를 구성하여 고가용성과 확장성을 제공합니다.
Kafka는 클러스터 내 여러 브로커에 각 파티션을 복제할 수 있습니다.
클러스터 내 브로커 중 하나가 파티션 리더로서 역할을 수행합니다.
각 파티션의 리더는 해당 파티션에 대한 모든 읽기 및 쓰기 요청을 처리하고, 팔로워 복제본들은 리더의 상태를 동기화합니다.
리더 브로커에 장애가 발생하면, 팔로워 중 하나가 자동으로 새로운 리더로 선출됩니다.
이러한 메커니즘 덕분에 브로커가 다운되더라도 데이터가 손실되지 않고, 동일한 파티션의 복제본을 가진 다른 브로커를 통해 계속 제공될 수 있습니다.
2.3. Metadata Management
브로커는 또한 Kafka의 정상적인 동작에 필수적인 대량의 메타데이터를 처리합니다.
예를 들어, 브로커는 새로운 토픽과 파티션의 생성을 추적하고, 이에 대한 메타데이터를 관리합니다.
여기에는 토픽 목록, 각 토픽이 가지고 있는 파티션 수, 그리고 클러스터 내 브로커들에 걸쳐 파티션이 어디에 위치하는지에 대한 정보가 포함됩니다.
2.4. Example of Data Interaction with Kafka Borkers
이러한 개념을 실제로 이해하기 위해, 프로듀서가 Kafka 브로커로 데이터를 전송하고, 컨슈머가 브로커로부터 데이터를 가져오는 과정을 보여주는 간단한 코드 예제를 살펴보겠습니다.
# Producer code example
from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('my-topic', b'Hello, Kafka!')
producer.flush()
# Consumer code example
from kafka import KafkaConsumer
consumer = KafkaConsumer('my-topic',
bootstrap_servers='localhost:9092',
auto_offset_reset='earliest')
for message in consumer:
print(f"Received message: {message.value.decode('utf-8')}")
3. Kafka Broker Management within a Cluster
전통적으로, ZooKeeper라는 외부 소프트웨어 컴포넌트가 브로커 메타데이터를 관리하고 클러스터 내 브로커 상태를 조율하는 데 사용되었습니다.
그러나 이로 인해 여러 상호작용과 의존성이 발생하여 Kafka 시스템 관리와 확장성이 복잡해졌습니다.
최근에는 (버전 3.3부터) Kafka가 KRaft를 통해 Zookeeper 없이 동작하는 Kafka로 전환되었습니다.
이 주제는 우리의 Kafka Zookeeper 장에서 자세히 다루며, 여기서는 간략히 개요만 설명합니다.
KRaft 프로토콜은 클러스터 내 브로커들이 스스로 메타데이터를 관리하고 리더 선출을 수행할 수 있도록 합니다.
이처럼 하나의 시스템으로 통합되면서 운영 복잡성이 줄어들고, 전체 시스템의 신뢰성이 향상되었습니다.
3.1. Quorum Controller
클러스터 내 브로커들은 컨트롤러 또는 투표자(voter) 역할을 할 수 있습니다.
컨트롤러는 클러스터 메타데이터를 관리하고, 합의 메커니즘을 통해 클러스터 전체의 상태를 일관되게 유지합니다.
이 컨트롤러들은 쿼럼(quorum)을 형성하는데, 이는 메타데이터 업데이트에 대한 합의 과정에 적극적으로 참여하는 Kafka 브로커들의 하위 집합을 의미합니다.
3.2. Metadata Log
클러스터 내의 모든 메타데이터 변경 사항은 Metadata Topic 또는 Event Store라고 불리는 특별한 Kafka 토픽에 이벤트들의 시퀀스(순서대로 기록된 사건들)로 저장됩니다.
Kafka는 이 로그를 컨트롤러들에 복제하여, 내구성(durability)과 장애 허용(fault tolerance)을 보장합니다.
로그에 기록된 각 이벤트는 새로운 토픽 생성이나 기존 토픽 수정과 같은 메타데이터 작업을 나타냅니다.
3.3. Leader Election
쿼럼 컨트롤러들은 Raft 합의 알고리즘을 사용하여 스스로 리더를 선출합니다.
리더는 모든 메타데이터에 대한 쓰기 요청(write requests)을 처리하고, 이러한 변경사항을 다른 컨트롤러(팔로워)들에게 복제(replication)하는 책임을 집니다.
장애가 발생할 경우 리더십이 다른 컨트롤러로 전환되어, 클러스터가 계속 운영될 수 있도록 보장합니다.
다이어그램 상의 Broker C가 리더 브로커인 경우, 메타데이터 토픽에 대한 모든 쓰기 작업을 담당합니다.
리더는 메타데이터 업데이트를 수락하고, 이를 메타데이터 토픽에 기록한 뒤, 다른 브로커들에게 이 변경사항을 전파합니다.
또한 리더는 주기적으로 메타데이터 상태를 스냅샷(snapshot)으로 저장하여 성능을 최적화하고, 메타데이터 토픽이 무한정 커지는 것을 방지합니다.
이러한 스냅샷 덕분에 브로커들은 전체 메타데이터 로그를 처음부터 모두 재생하지 않고도, 빠르게 복구하거나 부트스트랩할 수 있습니다.
3.4. Read Events
브로커들은 메타데이터 토픽(metadata topic)을 읽어 최신 클러스터 구성과 메타데이터 상태를 지속적으로 업데이트할 수 있습니다.
이를 통해 모든 브로커가 일관되고(consistently) 최신 상태의 메타데이터에 접근할 수 있도록 보장됩니다.
3.5. Safety
KRaft는 일관성을 유지하기 위해 안전성(safety) 속성을 보장합니다.
주어진 기간 동안 오직 하나의 리더만 선출될 수 있도록 하여, 여러 리더가 동시에 선출되어 충돌하는 로그 항목(conflicting log entries)이 발생하는 것을 방지합니다.
또한, 두 로그가 동일한 인덱스와 텀(term)을 가진 항목을 포함하고 있다면, 그 시점까지의 로그 내용은 반드시 동일하다는 것을 보장합니다.
이를 통해 모든 브로커에 걸쳐 커밋된 로그 항목(committed log entries)이 일치하도록 합니다.
KRaft는 클러스터 멤버십 변경(cluster membership changes)도 지원하여, 브로커가 클러스터에 동적으로 합류하거나 탈퇴할 수 있게 하면서도, 시스템의 안전성과 일관성을 유지할 수 있습니다.
4. Kafka Broker Challenges
이러한 개선에도 불구하고, Kafka 브로커 관리는 여전히 자체적인 과제를 안고 있습니다.
-버전 관리 (Version Control)
KRaft로의 전환은 여러 가지 도전을 수반합니다.
예를 들어, 기존 ZooKeeper 기반 구성에서 KRaft로 마이그레이션하는 것은 복잡하며, 상당한 수준의 배포 변경이 필요합니다.
또한, KRaft는 비교적 새로운 기술이기 때문에, 성숙한 ZooKeeper 기반 구성에 비해 안정성이나 기능 동등성(feature parity) 측면에서 이슈가 존재할 수 있습니다.
-구성(Configuration)
최신 버전을 배포하더라도, Kafka를 최적의 성능으로 구성하려면 수많은 설정과 파라미터에 대한 깊은 이해가 필요합니다.
이는 숙련된 사용자에게조차 버거운 작업이 될 수 있습니다.
이 설정에는 메모리 관리(memory management), 파일 I/O, 복제(replication), 그리고 컨슈머 그룹 조정(consumer group coordination) 등이 포함됩니다.
처리량(throughput), 지연(latency), 그리고 자원 활용(resource utilization) 간의 최적 균형을 이루려면, 깊은 기술적 전문성과 사용 패턴에 따른 지속적인 튜닝이 요구됩니다.
5. 기타
만약 파티션이 한 개만 있는데 토픽 내 파티션에 문제가 생기면 어떻게 되는가?
replilcation factor가 2 이상이고, 카프카 클러스터를 구성하는 브로커 서버의 개수가 2개 이상이면 다른 브로커 서버에 해당 파티션이 복제되어 있기 때문에 괜찮다.
그러나 replication factor가 1이고, broker도 1개 밖에 없는 클러스터라면 데이터 loss가 발생한다.
아래 예시 참고
Initially:
Partition 0
- Leader: Broker1
- Followers: Broker2, Broker3
After Broker1 fails:
Partition 0
- New Leader: Broker2
- Follower: Broker3
replication factor의 기본값은 1이고, topic 생성할 때 아래와 같이 설정할 수 있다.
kafka-topics.sh --create \
--topic my-topic \
--bootstrap-server localhost:9092 \
--partitions 3 \
--replication-factor 1