Apache Kafka는 실시간 데이터를 fault-tolerant한 방식으로 다룰 수 있게 도와주는 분산 스트리밍 데이터 플랫폼이다.

분산 아키텍처로서 Kafka 클러스터는 단일 머신으로 구성되기보다 여러 머신을 붙여서 사용하는 것이 일반적이다. 이때, 분산 환경을 관리하는 플랫폼인 Apache Zookeeper가 등장한다.

Zookeeper와 Kafka는 다음과 같은 상호작용을 수행한다.

1. Broker Registration: Kafka 브로커가 시작되는 경우 Zookeeper에 본인을 등록한다. 해당 정보는 Zookeeper 내부의 ephemeral node 내부에 등록되며, 등록이 완료되었다면 Zookeeper를 통해 해당 브로커가 Kafka 클러스터 내부에 존재하게 된다.

2. Broker Discovery: Kafka 클라이언트(producer, consumer)는 Zookeeper를 통해 사용가능한 Kafka 브로커가 있음을 알 수 있다. 클라이언트가 zookeeper에게 쿼리를 날려 현재 활성화된 브로커의 리스트와 그들의 메타데이터를 확인하는 방식으로 수행된다.

3. Leader Election: Kafka에서 토픽을 구성하는 각 파티션은 해당 파티션을 처리하는 Leader 브로커가 존재한다. 이어서 해당 Kafka 클러스터를 구성하는 다른 브로커 노드는 Follower 브로커로서 해당 Leader를 따른다. leader는 해당 파티션에 해당하는 메세지를 읽고 쓰는 작업을 다루게 되며, Follower는 해당 데이터를 복제하여 가진다. 이때 Zookeeper는 Leader가 실패하는 경우를 감지하고 새로운 리더를 선출(Elect)한다.

4. Configuration Management: Kafka는 Zookeeper를 활용하여 topic을 저장하거나 할당량을 지정하여, 이를 다른 브로커들에게 전파한다. configuration 상에 변화가 발생하면 kafka는 이를 Zookeeper에 기록하고 이는 다른 모든 브로커에게도 전파된다.

5. Cluster Coordination
: Zookeeper는 서로 다른 여러 브로커가 서로 협력해야 하는 경우 동기화 작업을 제공하는 방법 중 하나이다. 예를 들어 토픽이 생성되거나 브로커가 클러스터에 추가되는 경우, 동기화 작업이 요구된다. Cluster Coordination를 좀 더 알아보고 싶다면, 이어지는 글에 추가적인 설명을 적어놓았으니 참고바란다.

 

version: '3'

services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    volumes:
      - zookeeper-data:/var/lib/zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka1:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka1:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

  kafka2:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 2
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka2:9093
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

 


KAFKA_ADVERTISED_LISTENERS
 파라미터는 Kafka가 자신의 IP/포트를 export하는 방법을 지정하여 다른 Kafka broker, client(producer 또는 consumer) 및 Zookeeper와 같은 다른 요소가 연결할 수 있도록 한다. 특히 Docker 내에서 Kafka를 실행할 때 중요한데, 기본적으로 docker로 Kafka 환경을 구성한다면, 각 컨테이너는 Docker 내부 IP를 발행하므로 이를 연결하기 위해서는 도커 네트워크를 명시적으로 생성하거나 또는 docker compose를 통해 자동으로 구성된 도커 네트워크를 사용해야 한다.

 

또 중요한 점으로 Zookeeper 인스턴스는 Kafka 노드를 적극적으로 감지하지 않는다는 점이다. 대신 Kafka 노드 측에서는 시작할 때 Zookeeper에 자신을 등록하는 형태로 Zookeeper ephemeral node에 본인을 등록한다. 각 Kafka broker는 Zookeeper 세션을 유지하며, 만약 세션이 만료된다면 (ex. Broker가 충돌하거나, Zookeeper와 통신이 끊어지는 경우), Zookeeper는 브로커를 더 이상 존재하지 않는 것으로 간주하고 Broker registry에서 제거한다.

 

일단 Kafka Broker가 Zookeeper에 등록되면 연결 정보가 Zookeeper의 /brokers 하위 노드에 저장되고 이는 다른 Broker, Consumer 및 Producer가 해당 Broker에 연결을 구성할 때 사용된다.

 

Zookeeper 인스턴스는 Kafka 노드를 적극적으로 "감지"하지 않습니다. 대신, Kafka 노드는 시작할 때 Zookeeper에 자신을 등록합니다. 각 Kafka 브로커는 Zookeeper 세션을 유지하며, 세션이 만료되면 (예: Kafka 브로커가 충돌하거나 Zookeeper 앙상블과 통신할 수 없는 경우), Zookeeper는 브로커를 더 이상 존재하지 않는 것으로 간주하고 브로커 레지스트리에서 제거합니다.

 

PLAINTEXT는 보안 설정이 되지 않는 연결 프로토콜을 의미한다. 그 외에도 SSL, SASL_PLAINTEXT, SASL_SSL 과 같은 보안 연결 프로토콜로도 세션 연결이 가능하다. 다만 이 경우에는 SSL을 구성하기 위한 일반적인 시나리오가 요구된다. (인증서/키 등을 관리할 솔루션이 추가적으로 요구)