본문 바로가기
Node js/Nest js 강의 내용

9. Kafka 설명 & 연동 (한방에 해결하자)

by Bill Lab 2025. 1. 27.
728x90

1. Kafka 란?

    : Apache 재단에 등록된 오픈소스로써, 분산형 스트리밍, 대규모 트래픽처리, 대용량 데이터 처리를 원활하게 처리하기 Message Queue (https://kafka.apache.org/)

 

Apache Kafka

Apache Kafka: A Distributed Streaming Platform.

kafka.apache.org

 

 

2. Kafka 구조 및 흐름

     : kafka 의 구성은 main 의 역할인 kafka와 헬스체크 등 보조적인 역할인 zookeeper 가있다.

     (최근에 zookeeper 의 의존성을 없애기 위해 kafka 단독으로 개발하여 나온 툴이 있는데,

      zookeeper 대비 개선점은 확인되지 않는다.)

 

     1) Kafka 기본구조

       

https://www.tutorialspoint.com/apache_kafka/apache_kafka_cluster_architecture.htm

   

     2) Producer

출처:https://kirti-garg0410.medium.com/apache-kafka-architecture-kafka-component-overview-ac7acfd0ec85

 

Producer는 데이터를 파티션에 따라 특정 브로커(리더)로 전송합니다. 
전송 후 리더 브로커는 데이터를 먼저 받아 저장하고 바로 팔로워들에게 복제됩니다. 
(Producer가 데이터를 리더 브로커에 보냄, 리더 브로커가 해당 파티션에 대한 주 데이터 저장소로 데이터를 기록, 팔로워 브로커도 데이터를 가져옴)
복제는 리더가 데이터를 받는 즉시 발생하는 것이 아니라, 리더가 데이터를 기록한 후에 복제 프로세스가 진행됩니다.



     3) Consumer

출처:https://kirti-garg0410.medium.com/apache-kafka-architecture-kafka-component-overview-ac7acfd0ec85

 

 

     4) Kafka Topic 및 Partition 구조 (/w Offset)

출처:https://kirti-garg0410.medium.com/apache-kafka-architecture-kafka-component-overview-ac7acfd0ec85

 

     5) Key

카프카 공식 사이트
kafka 공식 사이트

 

     6) Kafka broker 및 replication (Confluent version)

출처: confluent

 

 

3. Kakfa setting 방법

    : Kafka 를 세팅하는 방법에는 아래와 같이 여러가지가 있다.

     그 중 우리는 3번으로 세팅해 보겠다(Docker Compose 기반)

 

    1) on premise 로 직접 설치

    2) docker 로 하나씩 띄우기

    3) docker compose 로 한번에 띄우기 

    4) K8S 내 yaml 로 띄우기

    5) K8S 내 kustomise 로 띠우기

    6) K8S 내 helm 으로 직접 설치하기

    

 

4. Kafka docker compose로 띄우기

    (Docker compose 가 설치되어있지 않는 경우 설치부터 하자!)

brew install cask docker-compose

 

     아래는 Docker Compose 파일이다

version: "1"

services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 3000
      ZOOKEEPER_INIT_LIMIT: 5
      ZOOKEEPER_SYNC_LIMIT: 2
      ZOOKEEPER_SERVER_ID: 1

  kafka-cluster1:
    image: confluentinc/cp-kafka:latest
    ports:
      - "9092:9092"
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka-cluster1:29092,EXTERNAL://localhost:9092
      KAFKA_NUM_PARTITIONS: 3
      KAFKA_DEFAULT_REPLICATION_FACTOR: 3

  kafka-cluster2:
    image: confluentinc/cp-kafka:latest
    ports:
      - "9093:9093"
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 2
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka-cluster2:29093,EXTERNAL://localhost:9093
      KAFKA_NUM_PARTITIONS: 3
      KAFKA_DEFAULT_REPLICATION_FACTOR: 3

  kafka-cluster3:
    image: confluentinc/cp-kafka:latest
    ports:
      - "9094:9094"
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 3
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka-cluster3:29094,EXTERNAL://localhost:9094
      KAFKA_NUM_PARTITIONS: 3
      KAFKA_DEFAULT_REPLICATION_FACTOR: 3

 

       위의 docker compose 파일(파일명: docker-compose-kafka.yml)을 실행하려면

       docker-compose -f docker-compose-kafka.yml up -d

       

           

5. Nest 연동

   

yarn add @nestjs/microservices kafkajs or pnpm i @nestjs/microservices kafkajs

 

 

6. 주문로직 리펙토링

     1) 리펙토링 이유?

          : 리펙토링을 하지 않아도 잘 돌아가는데 왜해야하는 걸까?

            - 두개의 모듈로 각각 처리함으로써 DB 트랜젝션 범위 축소

            - order service 에서 cart repo 와 order repo를 직접 참조하면서 수행하던 부분을 완전한 분리(느슨한 결합)

              → 향후 micro service 분리 시에도 바로 분리 가능

                   (단, Kafka 이슈 또는 Consumer 가 제대로 동작하지 않았을때 대체방안이 필요

 

      2) 분리 방법?

           : Kafka를 이용한 이벤트 처리로 분리

   

      3) 한계?

           - 코드레벨에서 복잡성이 상승

           - DB 트랜젝션 및 락을 직접사용할 수 없기때문에 코드레벨로써 트랜젝션기능을 수행해야함

             (분산락, Saga pattern 등 - 이후과정에서 진행예정)

           - producer 이후 오류 발생 시 적절한 대처가 필요(Transactional outbox pattern 등 - 이후 과정으로 진행예정)

 

 7. Kafka Ui

Broker 현황, Topics 현황 및 저장된 Messages 정보, 각 토픽별 Offset 위치, 소비하고 있는 consumer의 group과 현황 등을 바로 알 수 있다.

 

version: "2"
services:
  kafka-ui:
    image: provectuslabs/kafka-ui
    container_name: kafka-ui
    ports:
      - "8989:8080"
    restart: always
    environment:
      - KAFKA_CLUSTERS_0_NAME=local
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka-cluster1::29092,kafka-cluster2:29093,kafka-cluster3:29094
      - KAFKA_CLUSTERS_0_ZOOKEEPER=zookeeper:2181
728x90