기타

카프카 2트

99duuk 2025. 4. 28. 18:35

https://towardsdev.com/kafka-101-a-beginners-guide-to-understanding-kafka-2cd797864614

 

Kafka 101: A Beginner’s Guide to Understanding Kafka

Apache Kafka has become a critical infrastructure tool for building real-time data pipelines, event-driven architectures, and streaming applications. However, its terminology, architecture, and…

towardsdev.com

 

 

 

 

Kafka에서 핵심이 되는 구조는

토픽(Topic), 파티션(Partition), 브로커(Broker), 컨슈머 그룹(Consumer Group)이다.

 

Kafka의 토픽은 하나의 데이터 스트림을 저장하는 단위이고,

이 토픽은 여러 개의 파티션으로 나뉘어진다.

각 파티션은 실제 데이터가 저장되고 처리되는 최소 단위이다.

 

 

파티션은 항상 하나의 리더 브로커(Leader Broker)가 담당하고,

나머지 브로커들은 팔로워(Follower)로서 리더의 데이터를 복제하는 역할을 한다.

리더 브로커는 모든 읽기/쓰기 작업을 담당하고, 팔로워 브로커는 단순히 데이터를 백업하는 역할만 한다.

리더 브로커가 죽으면, 팔로워 브로커 중 하나가 리더로 승격되어 무중단 장애 복구가 가능하다.

복제되는 단위는 파티션이며, 하나의 브로커는 여러 토픽의 여러 파티션을 가질 수 있다.

 

 

Kafka에서 컨슈머 그룹은 하나의 목적을 가진 소비자 집합이다.

컨슈머 그룹 안에서는 각 파티션을 나눠서 읽으며,

한 파티션은 동시에 한 컨슈머만 읽는다.

같은 컨슈머 그룹 내에서는 한 파티션을 여러 컨슈머가 동시에 읽을 수 없다. (메시지 순서를 보장하기 위해서)

 

반면, 서로 다른 컨슈머 그룹들은 같은 토픽을 독립적으로 읽을 수 있다.

서로 영향을 전혀 주지 않고, 각자 별도의 오프셋(Offset, 읽은 위치)을 관리한다.

Kafka는 컨슈머 그룹마다 별도로 오프셋을 관리한다. 오프셋 정보는 내부 토픽인 __consumer_offsets에 저장된다.

 

만약 A라는 토픽을

김 컨슈머 그룹, 최 컨슈머 그룹, 박 컨슈머 그룹이 각각 읽고 있다고 해보자.

이때 김 그룹이 엄청 빠르게 모든 메시지를 읽어버리더라도,

최 그룹과 박 그룹은 자기들의 오프셋을 기준으로 천천히 읽는다.

 

김 그룹이 빨리 읽는다고 해서 다른 그룹의 읽을 수 있는 데이터가 없어지지 않는다.

Kafka는 메시지를 읽었다고 바로 삭제하지 않는다.

메시지는 설정된 Retention 기간(예: 7일) 동안 유지되고, 기간이 지나야 삭제된다.

만약 Retention 기간 안에 컨슈머 그룹이 메시지를 다 읽지 못하면,

Kafka는 메시지를 삭제하고, 남아있는 컨슈머 그룹은 OffsetOutOfRangeException 같은 에러를 만나게 된다.

 

 

 

 

과거 spring에 elk 붙혔던 것에서 logstash -> kafka 로 변경했다고 가정하면, 

 

elk 스택을 활용한 데이터베이스 연동

https://github.com/LuckyVickys/woosan-back|  도입 우산 프로젝트는 ElasticSearch를 사용해서 검색 기능을 구현했다.구현이 용이하도록 간단하고 쉽게 설계한 뒤, 네이버 클라우드 플랫폼 바우처가 있을 때

99duuk.tistory.com

 

Kafka에서는 소스 시스템 하나에서 발생한 이벤트를, 여러 컨슈머 그룹이 각각 다른 방식으로 소비할 수 있다. 

  • 로그 수집용 컨슈머 그룹
  • 타겟 시스템 전송용 컨슈머 그룹
  • 초성 추출용 컨슈머 그룹
  • 검색어 수집용 컨슈머 그룹

이렇게 분리할 수 있다. 각 컨슈머 그룹은 독립된 오프셋을 가지고, 같은 메시지를 읽더라도 각자의 목적에 맞게 처리할 수 있다.

  1. Input (JDBC)
    • MySQL에서 5초마다 주기적으로 데이터 변경을 폴링했다.
    • sql_last_value를 기준으로 변경된 데이터만 가져왔다.
  2. Filter
    • 필요 없는 필드를 제거하고, 새로운 메타데이터를 추가했다.
    • title과 content를 복사하여 synonym 필드를 만들었다.
    • ruby 코드를 이용해 한글 초성 추출을 수행했다.
  3. Output
    • board 인덱스로 게시글을 저장하거나 삭제 처리했다.
    • 검색어 수집은 search_keywords 인덱스에 저장했다.

 

하지만 이 구조는 기본적으로 주기적인 폴링(Pull) 기반이었고, 하나의 Logstash 프로세스가 모든 역할(동기화, 초성추출, 검색어 저장 등)을 담당하는 구조였다.

 

 

 

Kafka로 구조를 변경하면 다음과 같은 변화가 생긴다:

  • 소스 시스템(DB 등)에서 변경이 발생할 때마다 Kafka Producer가 토픽에 메시지를 발행한다. (Push 방식)
  • 토픽은 목적별로 여러 컨슈머 그룹이 구독할 수 있다.
  • 각각의 컨슈머 그룹은 독립적으로 메시지를 소비하고, 별도로 가공 및 저장할 수 있다.

예를 들면:

  • es-sync-group: 원본 데이터 Elasticsearch 저장
  • chosung-extract-group: title, content 초성 추출 후 저장
  • tokenizing-group: 문장 토크나이징 후 저장
  • search-tracking-group: 검색어 조회 기록 저장

이렇게 구분할 수 있다.

 

가벼운 작업(초성 추출, 검색어 저장)끼리는 하나로 묶을 수도 있다.

묶을지 분리할지는 리소스 사용량, 작업 복잡도에 따라 결정하면 된다.

 

만약 특정 작업(예: 토크나이징)이 CPU, 메모리를 많이 잡아먹어서 병목이 생긴다면,

  • 해당 컨슈머 그룹의 컨슈머 수를 늘리고,
  • 토픽의 파티션 수도 늘려서 병렬 처리를 강화할 수 있다.

 

 

Kafka에서는 다음과 같은 Partition 설계 방법이 필요하다:

  • 예상하는 컨슈머 수 이상으로 파티션을 만든다.
  • 초당 데이터 처리량을 고려해서 파티션 수를 잡는다. (보통 1파티션당 1~10MB/s 기준)
  • 키를 잘 설정해야 한다. (user_id, order_id 등 고유한 식별자 사용 추천)
  • 파티션은 줄일 수 없고, 늘릴 수만 있으니 처음에 여유 있게 잡는다.

 

Consumer Lag이 발생하면 (즉, 아직 읽지 못한 메시지가 쌓이면):

  • 컨슈머 수를 늘리거나,
  • 파티션 수를 늘리거나,
  • 컨슈머 코드 최적화 (병목 줄이기)를 해야 한다.

Consumer Lag은 실시간 모니터링 도구를 이용해서 관리하는 것이 중요하다. (Kafka Manager, Burrow 등)

Consumer Commit 방법에도 주의해야 한다:

  • auto.commit은 주기적으로 자동 커밋되지만 신뢰성이 떨어진다.
  • manual commit은 처리 완료 후 명시적으로 커밋해서 데이터 손실 위험을 줄일 수 있다.

 

Kafka는 단순히 메시지 큐가 아니라, 대규모 분산 스트리밍 플랫폼이다.

  • 파티션으로 수평 확장,
  • 컨슈머 그룹으로 목적 분리,
  • 실시간/병렬 처리,
  • 장애 복구,
  • 다양한 스트리밍 패턴(Exactly-once, At-least-once, 등)까지 지원한다.

 

Kafka로 변경하면서 실시간성, 확장성, 장애 격리성, 유연성이 기존 Logstash Polling 기반 구조보다 훨씬 좋아진다.

마지막으로, 이 흐름을 PlantUML로 시각화했다.

 

 

 

 

 

'기타' 카테고리의 다른 글

장자 길라잡이 76 - 두려워 말라  (0) 2025.12.30
지피티야 미안해  (0) 2025.06.29
전략 패턴  (0) 2025.04.28
ArrayList와 HashSet 만들어보기.. C++  (1) 2025.03.03
Vim 마스터의 길...  (0) 2025.03.03