imhamburger 님의 블로그

데이터엔지니어 부트캠프 - 다섯번째 팀프로젝트 (11/11 ~ 11/13) (18주차) 본문

데이터엔지니어 부트캠프

데이터엔지니어 부트캠프 - 다섯번째 팀프로젝트 (11/11 ~ 11/13) (18주차)

imhamburger 2024. 11. 17. 17:13

이번에 진행한 팀프로젝트는 파이널  프로젝트를 위한 빌드업으로 docker compose로 모든 어플리케이션을 실행하는 환경을 구축하였다.

이번에도 주어진 시간은 3일이었고 파이널프로젝트 아키텍쳐를 기반으로 각자의 역할을 정했다.

 

그 중 나의 역할은 kafka를 docker compose로 띄우는 것이었다.

 

 

팀프로젝트 주제

  • 똑같은 개발환경에서 개발 가능 하도록 (docker, docker compose, minikube, k3s ... 등등 적합한것 활용)
  • prometheus - grafana - exporter 대시보드 만들기
  • prometheus 로 수집된 모니터링 지표 관리 프로그램에 연결
  • scale 조정 관리 화면 만들기

 

나의 역할

  • Kafka를 docker compose로 설정하기
  • kafka 실행 로그를 prometheus와 grafana 로 시각화하기
  • kafka로 데이터를 받아 MariaDB에 적재하기

 

내가 사용한 기술 스택

1. Apache Kafka

2. Docker compose

3. Prometheus

4. Grafana

5. MariaDB

 

 

우선, Kafka Producer와 Consumer는 만들어놓았고 Dependencies 가 있기 때문에 requirements.txt 파일을 만들어 Dockerfile로 묶었다.

 

Dockerfile

FROM python:3.11

# 작업 디렉터리 설정
WORKDIR /app

# 필요한 패키지 설치
RUN apt-get update && apt-get install -y bash && apt-get install -y vim

# requirements.txt 파일 복사 및 패키지 설치
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt

# 나머지 코드 파일 복사
COPY src/semi_final /app
COPY kafka-config.yaml /app/kafka-config.yaml

# 기본 명령어 설정 (여기서는 별도로 설정하지 않고 docker-compose에서 설정)

 

 

kafka-config.yaml

kafka:
  producer:
    bootstrap_servers: "kafka1:9092"
    topic: "tickets"
    retries: 3
    acks: "all"

  consumer:
    bootstrap_servers: "kafka1:9092"
    group_id: "ticket"
    topics:
      - "tickets"
    auto_offset_reset: "earliest"
    enable_auto_commit: false

 

  • bootstrap_servers: Kafka 클러스터의 브로커 주소를 지정. Kafka 클러스터에 연결할 수 있는 최소한의 브로커를 설정해 주어야 하며, kafka1:9092는 kafka1이라는 호스트에서 9092 포트로 Kafka 서버에 접근하는 설정.
  • topic: 메시지를 전송할 Kafka의 토픽을 지정. 여기서는 tickets라는 토픽에 메시지를 보내는 설정.
  • retries: 메시지 전송에 실패했을 때, 자동으로 재시도할 횟수를 설정. 3번까지 재시도하도록 설정.
  • acks: 메시지 전송 후 Kafka 브로커의 응답 방식을 지정. "all"은 모든 브로커가 메시지를 받았다고 확인한 후에만 producer가 응답을 받도록 설정하는 옵션으로, 데이터의 내구성을 보장하는 설정.

 

acks에 관련해서는 별도로 정리해두었으니 참고!! (바로가기)

 

 

 

docker-compose.yaml

services:
  kafka1:
    image: bitnami/kafka:3.1.0
    container_name: kafka1
    environment:
      - KAFKA_BROKER_ID=1
      - KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka1:9092
      - KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
      - KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
      - KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
      - KAFKA_CFG_MIN_INSYNC_REPLICAS=2
    ports:
      - "9092:9092"
    deploy:
      resources:
        limits:
          memory: "16G"
          cpus: "4"
        reservations:
          memory: "8G"
          cpus: "2"
    depends_on:
      - zookeeper1
      - zookeeper2
      - zookeeper3
    restart: on-failure
    networks:
      - kafka_network

  kafka2:
    image: bitnami/kafka:3.1.0
    container_name: kafka2
    environment:
      - KAFKA_BROKER_ID=2
      - KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9093
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka2:9093
      - KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
      - KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
      - KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
      - KAFKA_CFG_MIN_INSYNC_REPLICAS=2
    ports:
      - "9093:9093"
    deploy:
      resources:
        limits:
          memory: "16G"
          cpus: "4"
        reservations:
          memory: "8G"
          cpus: "2"
    depends_on:
      - zookeeper1
      - zookeeper2
      - zookeeper3
    restart: on-failure
    networks:
      - kafka_network

  kafka3:
    image: bitnami/kafka:3.1.0
    container_name: kafka3
    environment:
      - KAFKA_BROKER_ID=3
      - KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9094
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka3:9094
      - KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
      - KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
      - KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
      - KAFKA_CFG_MIN_INSYNC_REPLICAS=2
    ports:
      - "9094:9094"
    deploy:
      resources:
        limits:
          memory: "16G"
          cpus: "4"
        reservations:
          memory: "8G"
          cpus: "2"
    depends_on:
      - zookeeper1
      - zookeeper2
      - zookeeper3
    restart: on-failure
    networks:
      - kafka_network

  zookeeper1:
    image: bitnami/zookeeper:3.6.3
    container_name: zookeeper1
    hostname: zookeeper1
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_MY_ID=1
        #- ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889
      - ZOO_TICK_TIME=2000  # 2초
      - ZOO_INIT_LIMIT=10   # 초기 연결 제한 시간
      - ZOO_SYNC_LIMIT=5    # 동기화 제한 시간
    ports:
      - "2181:2181"
    networks:
      - kafka_network

  zookeeper2:
    image: bitnami/zookeeper:3.6.3
    container_name: zookeeper2
    hostname: zookeeper2
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_MY_ID=2
        #- ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889
      - ZOO_TICK_TIME=2000  # 2초
      - ZOO_INIT_LIMIT=10   # 초기 연결 제한 시간
      - ZOO_SYNC_LIMIT=5    # 동기화 제한 시간
    ports:
      - "2182:2181"
    networks:
      - kafka_network

  zookeeper3:
    image: bitnami/zookeeper:3.6.3
    container_name: zookeeper3
    hostname: zookeeper3
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_MY_ID=3
        #- ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889
      - ZOO_TICK_TIME=2000  # 2초
      - ZOO_INIT_LIMIT=10   # 초기 연결 제한 시간
      - ZOO_SYNC_LIMIT=5    # 동기화 제한 시간
    ports:
      - "2183:2181"
    networks:
      - kafka_network

  producer:
    build: .                   # Dockerfile로 이미지 빌드
    image: kafka-producer
    container_name: kafka-producer
    working_dir: /app
    volumes:
      - ./src/semi_final:/app
      - ./kafka-config.yaml:/app/kafka-config.yaml
    environment:
      - KAFKA_CONFIG=/app/kafka-config.yaml
    command: python /app/pro.py
    depends_on:
      - kafka1
      - consumer
    restart: on-failure
    networks:
      - kafka_network


  consumer:
    build: .
    image: kafka-consumer
    container_name: kafka-consumer
    working_dir: /app
    volumes:
      - ./src/semi_final:/app
      - ./kafka-config.yaml:/app/kafka-config.yaml
    environment:
      - KAFKA_CONFIG=/app/kafka-config.yaml
      - DB_USER=${DB_USER}   # 환경 변수로 DB_USER 사용
      - DB_PASSWORD=${DB_PASSWORD}   # 환경 변수로 DB_PASSWORD 사용
    command: python /app/con.py
    depends_on:
      - kafka1
    restart: on-failure
    networks:
      - kafka_network

networks:
  kafka_network:
    driver: bridge

 

  • KAFKA_BROKER_ID: Kafka 클러스터에서 이 브로커의 고유 ID를 지정. 클러스터 내의 각 브로커는 고유한 ID를 가져야 한다.
  • KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true: 새로운 토픽이 자동으로 생성되도록 설정. Kafka는 기본적으로 토픽이 없으면 자동으로 생성하지만, 이 값을 false로 설정하면 자동 생성이 비활성화.
  • KAFKA_ZOOKEEPER_CONNECT: Kafka 브로커가 연결할 Zookeeper 인스턴스들의 주소를 지정 (zookeeper1, zookeeper2, zookeeper3)가 2181 포트를 통해 연결
  • ALLOW_PLAINTEXT_LISTENER: Kafka가 암호화되지 않은(PLAINTEXT) 연결을 허용할지 여부를 설정
  • KAFKA_LISTENERS: Kafka가 수신할 네트워크 주소를 지정
  • KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka1:9092: 다른 Kafka 브로커나 클라이언트가 이 Kafka 브로커에 연결할 때 사용할 주소를 설정한다. 여기서는 kafka1:9092로 지정되어, Kafka 클러스터 내에서 다른 브로커나 클라이언트가 kafka1이라는 이름으로 이 브로커에 연결하게 된다.

 

Replica 설정

 

Kafka는 데이터의 내구성과 가용성을 높이기 위해 메시지를 여러 브로커에 복제한다. 관련 내용은 이전글을 참고!

 

  • KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2: Kafka의 __consumer_offsets 토픽(consumer 오프셋 정보를 저장하는 특수한 토픽)의 복제 팩터를 설정. 2로 설정되어 있으므로 이 토픽은 두 개의 브로커에 복제. 이를 통해 장애 발생 시 데이터를 복구할 수 있다.
  • KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2: 트랜잭션 상태 로그 토픽의 복제 팩터를 설정합니다. 트랜잭션을 지원하는 경우, 이 설정은 트랜잭션 상태 로그의 복제 수를 정의.
  • KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2: 트랜잭션 상태 로그에 대해 최소 ISR(In-Sync Replicas) 수를 설정한다. 이 값은 트랜잭션 상태 로그의 최소 동기화된 복제본 수를 의미. 2로 설정되어 있기 때문에 최소 두 개의 복제본이 동기화되어야 트랜잭션 로그에 기록할 수 있다.
  • KAFKA_CFG_MIN_INSYNC_REPLICAS=2: 일반적인 Kafka 토픽에 대해 최소 동기화된 복제본 수를 설정. 이 값은 메시지를 복제할 때 최소한 몇 개의 브로커가 동기화 상태여야 하는지 지정. 2로 설정되면, 최소 두 개의 브로커가 동기화되어 있어야만 메시지가 정상적으로 기록된다.

 

 

PLAINTEXT

암호화되지 않은(PLAINTEXT) 연결이란, 네트워크 통신을 할 때 데이터를 암호화하지 않고 평문(plain text) 형태로 전송하는 방식이다. 즉, 전송되는 데이터가 그대로 네트워크를 통해 송수신되며, 중간에서 누군가가 데이터를 가로채면 내용이 그대로 노출될 수 있다.
따라서.....
Kafka에서 데이터를 암호화하여 안전하게 전송하려면 SSL(Secure Socket Layer) 또는 TLS(Transport Layer Security) 암호화를 사용할 수 있다. 이를 통해 데이터를 암호화하여, 외부에서 가로채더라도 내용을 읽을 수 없도록 만들 수 있다.

 

TRANSACTION??

 

트랜잭션(Transaction)은 데이터베이스나 메시징 시스템에서 하나의 작업 단위로 간주되는 일련의 연산을 의미한다.

트랜잭션은 모든 연산이 완전하게 수행되거나 아예 수행되지 않거나 하는 원자성을 보장한다. 즉, 작업이 중간에 실패하거나 오류가 발생하면, 그 전까지의 모든 변경사항을 원상복구하고 완전한 상태를 유지한다. 

 

Kafka에서도 트랜잭션을 지원한다. Kafka의 트랜잭션은 메시지 생산자(producer)가 여러 메시지를 보내는 과정에서 일관성을 보장하고, 중간에 오류가 발생했을 때 메시지 전송을 취소할 수 있도록 도와준다. 예를 들어, 여러 메시지를 연속해서 전송하는데, 그 중 하나라도 실패하면 모든 메시지를 취소하고, 트랜잭션이 시작되기 전의 상태로 복구할 수 있다.

 

 

모든 설정을 완료 후 docker compose를 실행하면 된다!

 

 

Producer 로그 확인

 

 

그리고 외부서버에 있는 MariaDB 를 확인

 

 

 

내가 그린 카프카 클러스터 

 

 

 

나의 에러 리포트

 

에러 1) kafka.errors.NoBrokersAvailable: NoBrokersAvailable

Traceback (most recent call last):
  File "/app/pro.py", line 12, in <module>
    producer = KafkaProducer(
               ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/kafka/producer/kafka.py", line 381, in __init__
    client = KafkaClient(metrics=self._metrics, metric_group_prefix='producer',
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/kafka/client_async.py", line 244, in __init__
    self.config['api_version'] = self.check_version(timeout=check_timeout)
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/kafka/client_async.py", line 900, in check_version
    raise Errors.NoBrokersAvailable()
kafka.errors.NoBrokersAvailable: NoBrokersAvailable
[DONE]: 1.4495995044708252

 

발생이유

해당 에러는 브로커보다 프로듀서가 먼저 켜져서 생기는 오류였다. 아무래도 yaml 파일로 동시에 실행시키다보니 생기는 오류같았다.

(왜냐하면 아래 [DONE] 메세지는 제대로 작동된 것)

 

해결방법

브로커가 아직 준비되지 않았을 때 "연결중"이라는 메세지를 추가하였다.

 

브로커에 문제가 있을 시에는 다음과 같은 메세지 출력

 

 

에러 2) INFO shutting down (kafka.server.KafkaServer)

[2024-11-13 00:00:28,957] INFO shutting down (kafka.server.KafkaServer)
[2024-11-13 00:00:28,964] INFO App info kafka.server for 1 unregistered (org.apache.kafka.common.utils.AppInfoParser)
[2024-11-13 00:00:28,964] INFO shut down completed (kafka.server.KafkaServer)
[2024-11-13 00:00:28,964] ERROR Exiting Kafka due to fatal exception during startup. (kafka.Kafka$)
kafka.zookeeper.ZooKeeperClientTimeoutException: Timed out waiting for connection while in state: CONNECTING
	at kafka.zookeeper.ZooKeeperClient.$anonfun$waitUntilConnected$3(ZooKeeperClient.scala:257)
	at kafka.zookeeper.ZooKeeperClient.waitUntilConnected(ZooKeeperClient.scala:253)
	at kafka.zookeeper.ZooKeeperClient.<init>(ZooKeeperClient.scala:115)
	at kafka.zk.KafkaZkClient$.apply(KafkaZkClient.scala:2317)
	at kafka.zk.KafkaZkClient$.createZkClient(KafkaZkClient.scala:2407)
	at kafka.server.KafkaServer.initZkClient(KafkaServer.scala:748)
	at kafka.server.KafkaServer.startup(KafkaServer.scala:230)
	at kafka.Kafka$.main(Kafka.scala:112)
	at kafka.Kafka.main(Kafka.scala)
[2024-11-13 00:00:28,967] INFO shutting down (kafka.server.KafkaServer)

 

발생이유

Zookeeper를 3개로 늘렸을 때 연결이 안되는 문제였다.

 

Zookeeper 에러메세지는 다음과 같았다.

2024-11-13 00:50:30,508 [myid:] - ERROR [ListenerHandler-zookeeper1/192.168.16.2:3889:o.a.z.s.q.QuorumCnxManager$Listener$ListenerHandler@1099] - Exception while listening to address zookeeper1/192.168.16.2:3889
zookeeper2  | java.net.BindException: Cannot assign requested address (Bind failed)
zookeeper2  | 	at java.base/java.net.PlainSocketImpl.socketBind(Native Method)
zookeeper2  | 	at java.base/java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:452)
zookeeper2  | 	at java.base/java.net.ServerSocket.bind(ServerSocket.java:395)
zookeeper2  | 	at java.base/java.net.ServerSocket.bind(ServerSocket.java:349)
zookeeper2  | 	at org.apache.zookeeper.server.quorum.QuorumCnxManager$Listener$ListenerHandler.createNewServerSocket(QuorumCnxManager.java:1141)
zookeeper2  | 	at org.apache.zookeeper.server.quorum.QuorumCnxManager$Listener$ListenerHandler.acceptConnections(QuorumCnxManager.java:1070)
zookeeper2  | 	at org.apache.zookeeper.server.quorum.QuorumCnxManager$Listener$ListenerHandler.run(QuorumCnxManager.java:1039)
zookeeper2  | 	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
zookeeper2  | 	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
zookeeper2  | 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
zookeeper2  | 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
zookeeper2  | 	at java.base/java.lang.Thread.run(Thread.java:829)

 

발생이유

java.net.BindException: Cannot assign requested address (Bind failed) 오류는 ZooKeeper 인스턴스가 3889 포트에 바인딩하려고 할 때 실패했음을 나타낸다.

 

내가 작성한 Zookeeper yaml은 다음과 같았다.

zookeeper1:
    image: bitnami/zookeeper:3.6.3
    container_name: zookeeper1
    hostname: zookeeper1
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_MY_ID=1
      - ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889
      - ZOO_TICK_TIME=2000  # 2초
      - ZOO_INIT_LIMIT=10   # 초기 연결 제한 시간
      - ZOO_SYNC_LIMIT=5    # 동기화 제한 시간
    ports:
      - "2181:2181"
    networks:
      - kafka_network

  zookeeper2:
    image: bitnami/zookeeper:3.6.3
    container_name: zookeeper2
    hostname: zookeeper2
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_MY_ID=2
       - ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889
      - ZOO_TICK_TIME=2000  # 2초
      - ZOO_INIT_LIMIT=10   # 초기 연결 제한 시간
      - ZOO_SYNC_LIMIT=5    # 동기화 제한 시간
    ports:
      - "2182:2181"
    networks:
      - kafka_network

  zookeeper3:
    image: bitnami/zookeeper:3.6.3
    container_name: zookeeper3
    hostname: zookeeper3
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_MY_ID=3
      - ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889
      - ZOO_TICK_TIME=2000  # 2초
      - ZOO_INIT_LIMIT=10   # 초기 연결 제한 시간
      - ZOO_SYNC_LIMIT=5    # 동기화 제한 시간
    ports:
      - "2183:2181"
    networks:
      - kafka_network

 

해결방법

사실 아무리 구글링을 해보아도 해결법을 찾지 못하였었다. 엄청 헤맸었는데... 여러가지 실험끝에 오류를 해결할 수 있었다.

나의 해결방법은 ZOO_SERVERS=zookeeper1:2888:3889;zookeeper2:2888:3889;zookeeper3:2888:3889  이 줄을 없애니 정상적으로 실행되었다. (이유는 잘 모르겠다...)

 

 

에러 3) kafka broker - KAFKA_CFG_MIN_INSYNC_REPLICAS=2 로 설정시 오류

 

발생이유
min.insync.replicas=2로 설정되어 있기 때문에, 각 파티션에 대해 2개의 동기화된 복제본이 있어야 한다.
만약 세 번째 브로커가 동기화되지 않거나, 복제본이 동기화되지 않으면 이 오류가 발생할 수 있다.

해결방법
min.insync.replicas 값을 일시적으로 1로 낮추어 복제본 수를 1로 설정하면 오류를 우회할 수 있다. 그렇지만 이건 임시적인 방법이다.

따라서, 다음과 같은 옵션을 추가하여 해결하였다.

- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
- KAFKA_CFG_MIN_INSYNC_REPLICAS=2

 

해당 옵션은 위에 잘 설명되어있다!

 

 


팀프로젝트를 진행하면서...

 

좋은점

  • 핵심 기능 구현 완료: 시간의 제약이 있었지만 필수 기능을 모두 구현해 프로젝트의 기본 목표를 달성할 수 있었다.
  • 아파치 카프카 이해도 상승: 카프카를 yaml로 build하면서 acks, broker 그리고 zookeeper 관계에 대해 자세히 알 수 있었다.
  • 원활한 역할 분배: 역할이 적절히 분배되어 좋았다.
  • 이슈 활성화: 이슈를 활용하여 팀 내 커뮤니케이션이 원활했다.

 

아쉬운 점

  • Branch 전략 미흡: 사전에 branch 전략을 구체적으로 계획하지 않아 코드 기능 구분이 어려웠다.

 

개선할 점

  • 체계적인 Branch 전략 수립: 프로젝트 시작 전 branch 전략을 세우고 체계적으로 운영하여 협업 효율을 높여야 한다.

 

프로젝트 README 바로가기

 

 

 

다섯번째 팀프로젝트를 마치면서...

 

다섯번째 팀프로젝트를 진행하면서 Kafka에 대해 더욱 깊이 알게 되어 매우 흥미로웠다. 그동안 Kafka에 대해 알고 있던 내용은 사실 10% 정도밖에 되지 않았던 것 같다. Kafka를 직접 사용해 보면서 다양한 설정들을 했는데, 알고 있을수록 그만큼 쓰기가 더 어려워진다는 것을 느꼈다. 특히 에러 메시지를 해결하는 과정에서 난관을 겪으며, Kafka의 세부적인 동작 원리와 설정들이 얼마나 중요한지 절실히 깨닫게 되었다.

하지만 프로젝트를 진행하면서 팀원들과 역할을 잘 분배하고 협력하여 진행한 덕분에 예상보다 순조롭게 진행되었다. 각자 맡은 일을 책임감 있게 해주었고, 그것들이 하나로 모였을 때 시스템이 제대로 작동하는 모습을 보니 매우 신기하고 뿌듯한 마음이 들었다. 이렇게 협업을 통해 문제를 해결하는 과정이 매우 가치 있다는 생각이 들었다.

그럼에도 불구하고 아직 해결하지 못한 부분이 있다. 바로 branch 전략이 미흡하다는 것! 프로젝트가 커지면서 버전 관리와 브랜치 전략이 중요한 이슈가 되는데, 이를 체계적으로 관리하지 않으면 추후에 문제가 발생할 수 있겠다는 생각이 든다. 이를 보완하기 위한 전략이 필요하다는 점을 깨닫게 되었다.

한편, ADsP 시험이 끝난 후 조금 방심했던 것 같다. 이미 파이널 프로젝트를 시작한 지 2일이 지났지만, 아직까지 프로젝트의 진행 상황이 미흡하다. 그래서 이제부터는 더 집중해서 정말 열심히 해야겠다. 다음 주부터는 프로젝트 완성도를 높여 나가야겠다.