이벤트 브로커: 카프카(Kafka)

KDG: First things first!·2024년 11월 7일
0

Broker

목록 보기
2/3
post-thumbnail

메세지 큐와 브로커의 개념에 대해 잘 모르시는 분은 이전 포스팅인 MOM: 메세지 큐(Message Queue)와 브로커(Broker)을 정독하고 오시는 것을 권장합니다.


카프카(Kafka)란?

카프카(Apache Kafka) : 카프카는 대규모 실시간 데이터 스트리밍 및 이벤트 처리 시스템을 위한 분산형 메시징 시스템으로 여러 애플리케이션간에 데이터를 공유할 수 있게 하는 메시지 브로커 역할을 한다.


Kafka의 특징

  • 높은 처리량: kafka는 매우 높은 메시지 처리량을 자랑하기 때문에 대규모 데이터 스트리밍을 처리하는 데 적합하다.

  • 확장성: kafka는 수평적으로 확장이 가능하여 클러스터에 브로커를 추가하여 처리 성능을 높일 수 있다.

  • 데이터 영속성: kafka는 메시지를 디스크에 영속적으로 저장되며, 여러 복제본을 통해 내구성을 보장하기 때문에 데이터가 손실될 염려가 없다.

  • 실시간 처리 : kafka는 실시간으로 데이터를 처리할 수 있어, 이벤트 기반 아키텍처에 적합하다.

  • 분산 시스템: kafka는 분산 아키텍처로 설계되어 장애에 강하고, 데이터 손실 없이 메시지를 전달할 수 있다.


Kafka 주요 구성 요소

Producer

Producer: 데이터를 kafka로 보내는 주체로 Producer는 데이터를 특정 토픽(Topic)에 담아 전송한다.

  • 메시지 전송 시 Batch 처리가 가능하다.
  • key값을 지정하여 특정 파티션으로만 전송이 가능하다.
  • 전송 acks값을 설정하여 효율성을 높일 수 있다.
    • ACKS=0(확인 응답 기다리지 X) -> 매우 빠르게 전송. 파티션 리더가 받았는 지 알 수 없다.
      ACKS=1(리더 파티션의 응답만 필요) -> 파티션 리더가 받았는지 확인. 기본값
      ACKS=ALL(모든 복제 파티션의 응답 필요) -> 파티션 리더 뿐만 아니라 팔로워까(복제본을 보관하는 다른 파티션)지 메시지를 받았는지 확인

※ 전송 acks: Kafka의 acks(acknowledgments) 설정은 프로듀서(데이터를 보내는 쪽)가 메시지를 전송할 때 브로커가 어느 정도 수준의 확인 응답을 해야 전송을 성공했다고 간주할지를 설정하는 옵션이다.
acks 설정에 따라 데이터의 신뢰성과 지연 속도 간의 균형이 달라진다. 각 설정 값에 따라 메시지 전송 성공 여부가 결정되는 방식이 다르다.


Consumer

Consumer: Kafka에서 데이터를 소비하는 주체로 Consumer는 Kafka의 토픽에서 데이터를 읽어온다.

  • 메세지를 Batch 처리할 수 있다.
  • 한 개의 컨슈머는 여러 개의 토픽을 처리할 수 있다.
  • 메시지를 소비하여도 메시지를 삭제하지는 않는다. (Kafka delete policy에 의해 삭제)
  • 한 번 저장된 메시지를 여러번 소비도 가능하다.
  • 컨슈머는 컨슈머 그룹에 속한다.
  • 각 파티션은 동일한 컨슈머그룹 안에서 여러 개의 컨슈머에서 연결할 수 없다.(오직 하나의 컨슈머에만 연결)

Broker

Broker: Kafka 클러스터 내에서 데이터를 저장하고, Producer와 Consumer 간의 메시지를 중계하는 역할을 하는 서버로 Kafka는 여러 개의 브로커로 구성된 클러스터로 동작할 수 있다.

  • 현재 실행된 각 카프카 서버를 의미한다.
  • 프로듀서와 컨슈머는 별도의 애플리케이션으로 구성되는 반면, 브로커는 카프카 자체이다.
  • Broker(각 서버)는 Kafka Cluster 내부에 존재한다.
  • 서버 내부에서 메시지를 저장하고 발송하고 관리하는 역할을 수행한다.

Topic

Topic: Kafka에서 데이터를 분류하는 논리적 단위이다. Producer는 메시지를 설정한 특정 토픽으로 전송하고, Broker는 토픽을 저장하며, Consumer가 해당 토픽을 구독하여 메시지를 가져온다.

  • 각각의 메시지를 목적에 맞게 구분할 때 사용된다.
  • 메시지를 전송하거나 소비할 때 반드시 Topic을 입력해야 한다.
  • Consumer는 자신이 구독(담당)하는 Topic의 메시지를 처리한다.
  • 한 개의 토픽은 한 개 이상의 파티션으로 구성되어야 한다.

Partition

Partition: Kafka의 토픽은 여러 개의 파티션으로 나뉘어져 데이터를 분산 처리한다. 파티션은 메시지의 순서를 보장하고, 데이터를 병렬로 처리할 수 있도록 해준다.

데이터 중복 처리를 방지하기 위해 파티션은 한 컨슈머 그룹 내에서는 무조건 하나의 컨슈머하고만 연결되어야만 한다.


  • 분산 처리를 위해 사용된다.
  • Topic 생성 시 partition 개수를 지정할 수 있다.(파티션 개수 추가만 가능, 삭제 불가능)
  • 파티션이 1개라면 모든 메시지에 대해 순서가 보장된다.
  • 파티션 내부에서 각 메시지는 인덱스 같은 offset(고유 번호)로 구분된다.
  • 파티션이 여러개라면 Kafka 클러스터가 라운드 로빈 방식(순서대로 돌아가면서 작업을 처리)으로 분배해서 분산처리되기 때문에 메시지가 여러 파티션으로 분산되는 과정에서 순서가 보장되지 않는다.
  • 파티션이 많을 수록 처리량이 좋지만 장애 복구 시간이 늘어난다.

  • 각 파티션은 하나의 리더와 여러 개의 팔로워를 가질 수 있는데 이때 리더는 주키퍼에 의해 선출되고 파티션에 대한 모든 읽기/쓰기 요청을 처리하고, 팔로워들은 리더의 데이터를 복제한다.

Zookeeper

Zookeeper: Kafka는 Zookeeper를 사용하여 Kafka 클러스터의 메타데이터를 관리하고, 브로커의 상태를 모니터링하며, 파티션의 리더 선출을 처리한다.

  • 분산 애플리케이션 관리를 위해 리더 선출, 서버 간의 작업 분배, 임계 영역 관리 등을 실행하는 코디네이션 시스템이다.
  • 분산 메시지큐의 메타 정보를 중앙에서 관리하는 역할이다.

Consumer Group

Consumer Group: 하나 이상의 Consumer가 같은 Consumer Group으로 묶여 하나의 토픽을 병렬로 소비할 수 있도록 한다. 이 방식으로 메시지의 처리를 분산시키고, 각 메시지는 중복 없이 한 번만 소비되도록 할 수 있다.


Offset

Offset: Offset는 카프카에서 각 메시지가 파티션 내에서 저장되는 위치를 나타내는 고유한 번호이자 Consumer에서 메시지를 어디까지 읽었는지 저장하는데 활용되는 값이다.
카프카는 메시지를 순차적으로 기록하고, 각 메시지에 대해 파티션 내에서 고유한 offset을 할당한다. 이 offset을 통해 카프카 클러스터 내의 파티션에서 메시지를 구별하고, 각 컨슈머에서 특정 파티션의 데이터를 어디까지 읽어 갔는지 기록할 수 있어 메시지를 정확히 찾아서 읽을 수 있게 한다.

Consumer에서 데이터를 잘 가져갔으면 offset을 브로커에 전달하고 그럼 브로커에서는 __consumer_offsets 라는 저장 공간에 각 컨슈머 그룹에서 파티션 별로 어디까지 데이터를 가져갔는지 기록합니다.

offset을 통해서 컨슈머 그룹은 이전에 가져갔던 데이터를 다시 가져가는 중복 컨슘의 문제를 피할 수 있
다.

  • 컨슈머 그룹의 컨슈머들은 각각의 파티션에 자신이 가져간 메시지의 위치 정보(offset) 을 기록
  • 컨슈머 장애 발생 후 다시 살아나도, 전에 마지막으로 읽었던 위치에서부터 다시 읽어들일 수 있다.



Kafka 브로커의 역할

  • 메시지 저장: Kafka 브로커는 메시지를 디스크에 저장한다. 메시지는 특정 토픽의 특정 파티션에 저장되어, Consumer가 요청할 때 메세지를 읽을 수 있다.

  • 메시지 전달: Producer가 보낸 메시지를 저장하고, 이를 구독한 Consumer에게 전달하면 Consumer는 Kafka 브로커에서 데이터를 읽어온다.

  • 메시지 복제: Kafka는 데이터를 여러 브로커에 복제하여 내구성을 보장한다. 이로 인해 각 파티션에 대해 복제본이 여러 개 존재할 수 있다.


Kafka 클러스터는 여러 서버(브로커)로 구성되어 있으며, 그 각 브로커는 데이터를 저장하고 전달하는 "서버" 역할을 한다. Kafka 자체는 하나의 서버가 아니라, 여러 브로커와 Zookeeper를 포함한 분산 시스템이다.

Partition 사용 이유

여러 파티션을 사용함으로써 얻을 수 있는 주요 이점은 다음과 같다.

  1. 확장성(Scalability):
    하나의 파티션만 사용할 경우, 해당 파티션에 대한 읽기 및 쓰기 요청은 단일 서버(혹은 브로커)에 집중되기 때문에 만약 데이터 양이 많아지면, 하나의 서버로는 처리하기 어려운 상황이 발생할 수 있다.
    하지만 여러 파티션을 사용하면 데이터를 여러 서버에 분산시킬 수 있어, 데이터 양이 증가하더라도 시스템의 수평 확장이 가능해져 각 파티션이 독립적으로 운영되므로, 파티션 수를 늘리면 시스템 용량을 효율적으로 늘릴 수 있다.

  2. 병렬 처리 (Parallel Processing):
    각 파티션은 독립적인 단위로 메시지를 저장하고 처리하므로, 여러 컨슈머가 동시에 각 파티션에서 메시지를 읽어가서 동시에 작업 진행이 가능해진다. 즉, 파티션 수가 많을수록 더 많은 병렬 처리가 가능해져 전체 서비스의 작업 속도를 향상시킬 수 있다.
    예를 들어, 컨슈머 그룹에서 각 컨슈머가 하나의 파티션을 담당하면서 메시지를 병렬로 처리할 수 있다. 이로 인해 처리 속도가 빨라지고, 시스템이 더 많은 데이터를 빠르게 처리할 수 있다.

  3. 가용성 및 장애 대응 (Availability and Fault Tolerance):
    카프카는 파티션 복제를 통해 장애 복구와 고가용성을 보장한다. 각 파티션은 여러 개의 브로커에 복제본을 두고 있어서, 특정 브로커가 장애를 일으켜도 해당 파티션의 데이터를 다른 브로커에서 제공할 수 있다.
    복제된 파티션이 많을수록 시스템의 장애 대응 능력이 향상된다. 각 파티션이 다른 서버에 분산되어 있기 때문에, 데이터 손실을 최소화하고, 시스템의 가용성을 높일 수 있다.

  4. 부하 분산 (Load Balancing):
    파티션을 여러 개로 나누면, 읽기/쓰기에 대한 부하를 여러 서버에 고르게 분배할 수 있다.
    예를 들어, 쓰기 작업은 특정 파티션에만 집중되지만, 파티션 수가 많으면 각 서버로 분산되어 부하가 균등하게 나뉜다.
    이로 인해, 서버 자원(CPU, 메모리 등)을 효율적으로 활용할 수 있다.

  5. 유연한 파티션 재배치 (Flexible Partition Rebalancing):
    파티션 수를 늘리거나 줄일 수 있어 동적 확장에 유리하다. 시스템의 부하가 증가하면 새로운 파티션을 추가하여 처리량을 확장할 수 있고, 부하가 줄어들면 파티션을 조정하여 자원을 최적화할 수 있다.
    카프카는 파티션 재배치(파티션의 리더와 복제본을 다른 브로커로 이동)를 통해 이러한 유연성을 제공한다.

  6. 효율적인 데이터 배포 (Efficient Data Distribution):
    카프카는 메시지를 여러 파티션에 분배하여 효율적으로 데이터를 분산 저장하고, 각 파티션은 독립적인 로그로 저장된다. 이로 인해 대규모 데이터를 분산 처리하고 관리하는 데 유리하다.


결국 하나의 토픽을 여러 개의 파티션으로 나누는 이유는 카프카의 성능, 확장성, 병렬 처리, 가용성 등을 최적화하기 위해서이다.
여러 파티션을 활용하면 데이터 양이 많아지더라도 시스템을 수평적으로 확장할 수 있고, 병렬 처리와 부하 분산을 통해 더 효율적으로 데이터를 처리할 수 있다. 또한, 파티션의 복제를 통해 고가용성 및 장애 복구가 가능해진다.



컨슈머 그룹 사용 이유

컨슈머 그룹(Consumer Group)은 카프카에서 매우 중요한 개념으로, 여러 개의 컨슈머(Consumer)가 하나의 그룹을 이루어 토픽에서 메시지를 병렬로 처리하도록 하는 방식입니다. 이를 사용하는 이유는 성능 향상, 부하 분산, 장애 복구 등 여러 가지 장점이 있기 때문입니다. 주요 이유는 다음과 같습니다:

  1. 부하 분산 (Load Balancing):
    하나의 토픽에 여러 개의 컨슈머 그룹이 있다면, 각 컨슈머는 독립적으로 메시지를 처리하게 됩니다. 각 컨슈머는 그룹 내에서 하나의 파티션에만 메시지를 소비하게 되므로, 여러 컨슈머가 각각 다른 파티션을 처리하며 병렬로 작업을 분담합니다.
    이로 인해, 하나의 컨슈머가 처리할 수 있는 데이터 양을 초과할 경우 여러 컨슈머가 각각 다른 파티션을 담당하여 부하를 분산시킬 수 있다.

  2. 병렬 처리 (Parallel Processing):
    카프카에서 컨슈머 그룹을 사용하면, 여러 개의 컨슈머가 동일한 토픽을 처리하되, 각 컨슈머가 독립적인 파티션을 읽도록 함으로써 병렬 처리가 가능해진다.
    예를 들어, 하나의 토픽에 4개의 파티션이 있고 4개의 컨슈머가 같은 컨슈머 그룹에 속하면, 각 컨슈머는 각 파티션에서 독립적으로 메시지를 읽어온다. 이를 통해 처리 속도를 대폭 향상시킬 수 있다.

  3. 메시지 처리의 효율성 (Message Processing Efficiency):
    각 컨슈머가 하나의 파티션을 처리하기 때문에, 메시지의 순서 보장을 유지할 수 있다. 카프카는 파티션 단위로 메시지 순서를 보장하므로, 동일 파티션을 담당하는 컨슈머가 메시지를 처리하면 순서대로 메시지가 처리된다.
    여러 컨슈머가 있을 경우 메시지 처리가 병렬로 이루어져 효율성이 극대화된다.

  4. 확장성 (Scalability):
    카프카는 컨슈머 그룹을 통해 토픽에 대한 메시지 처리량을 수평적으로 확장할 수 있다. 예를 들어, 처음에는 2개의 컨슈머만 있을 때는 메시지가 두 개의 컨슈머에서만 소비되지만, 컨슈머 그룹에 새로운 컨슈머를 추가하면 파티션 수에 맞춰 자동으로 작업이 분배되어 성능이 향상된다.
    파티션의 수에 맞춰 컨슈머 그룹에 컨슈머 수를 확장할 수 있어, 수요에 맞는 유연한 확장이 가능하다.

  5. 장애 복구 및 내결함성 (Fault Tolerance & Resilience):
    카프카에서 컨슈머 그룹을 사용하면, 컨슈머 장애 시 다른 컨슈머가 대체하여 메시지를 소비할 수 있다. 예를 들어, 하나의 컨슈머가 장애로 중단되면, 같은 컨슈머 그룹에 속한 다른 컨슈머가 해당 파티션을 재배치 받아 메시지를 계속 처리할 수 있다.
    이렇게 함으로써, 시스템의 장애 복구가 용이하고, 전체 시스템의 가용성을 높일 수 있다.

  6. 중복 메시지 처리 방지 (Message Deduplication):
    컨슈머 그룹을 사용하면 각 파티션에 대한 메시지를 하나의 컨슈머만 읽을 수 있기 때문에, 중복 처리를 방지할 수 있다. 각 컨슈머는 자신에게 할당된 파티션에서만 메시지를 읽기 때문에, 다른 컨슈머가 이미 처리한 메시지를 중복해서 처리하는 일이 없다.
    이를 통해 정확한 데이터 처리가 보장된다.

  7. 메시지의 공평한 분배 (Fair Message Distribution):
    카프카는 파티션 수와 컨슈머 수에 맞게 메시지를 공평하게 분배한다. 각 파티션은 컨슈머 그룹 내에서 하나의 컨슈머에게만 할당되므로, 모든 컨슈머가 공평하게 메시지를 처리할 수 있다.
    이로 인해, 하나의 컨슈머가 지나치게 많은 메시지를 처리하는 일이 없고, 전체 시스템의 부하를 고르게 분산시킬 수 있다.

  8. 단일 파티션에 대한 메시지 순서 보장 (Message Ordering Within a Partition):
    카프카는 파티션 내에서 메시지 순서를 보장합니다. 컨슈머 그룹을 사용하면 각 컨슈머가 처리하는 파티션에서 메시지 순서를 보장하면서도, 여러 컨슈머가 동시에 다른 파티션을 처리하므로 순서 보장과 병렬 처리 두 가지를 동시에 만족할 수 있다.
    예를 들어, 중요한 이벤트를 순차적으로 처리해야 하는 경우, 동일한 파티션에서 메시지를 처리하는 컨슈머를 통해 순서를 보장하면서도 병렬 처리의 이점을 취할 수 있다.

  9. 스케일링과 고가용성 (Scaling and High Availability):
    컨슈머 그룹은 카프카의 고가용성과 수평 확장성을 지원한다. 컨슈머 그룹에 컨슈머를 추가하면, 더 많은 파티션을 처리할 수 있어 시스템의 성능과 처리 용량을 증가시킬 수 있다.
    또한, 컨슈머 그룹은 장애가 발생했을 때 다른 컨슈머가 장애를 자동으로 대체할 수 있어 시스템의 고가용성을 유지할 수 있다.


결론적으로 카프카에서 컨슈머 그룹을 사용하는 이유는 부하 분산, 병렬 처리, 확장성, 장애 복구, 메시지 중복 방지 등을 통해 시스템의 성능과 안정성을 극대화하기 위해서이다.
특히, 대규모 분산 시스템에서 많은 데이터를 효율적으로 처리하고, 여러 개의 컨슈머가 협력하여 토픽에서 메시지를 처리하는 방식으로, 성능과 안정성을 크게 향상시킬 수 있다.



특정 브로커 장애 발생 시

Kafka에서 특정 브로커가 장애를 일으키면 다음과 같은 단계로 복구 및 재분배가 이루어진다.


  1. 파티션 리더 이동:
    장애가 발생한 브로커가 특정 파티션의 리더로 지정된 상태였다면, 주키퍼(ZooKeeper) 또는 카프카의 내부 컨트롤러가 자동으로 이 파티션의 리더 역할을 다른 팔로워 브로커로 이동시킨다. 팔로워 브로커 중 하나가 새 리더로 지정되어 클라이언트 요청을 계속 처리할 수 있게 한다.

  2. 장애 복구와 데이터 일관성 유지:
    장애가 난 브로커가 복구되어 다시 클러스터에 참여하면, 카프카는 복제 데이터를 동기화하여 손실된 데이터가 없도록 한다. 이 과정에서 복제본의 오프셋 차이를 비교하고, 필요한 데이터를 새로 복제하여 동기화한다.

  3. 가용성 보장:
    카프카는 기본적으로 복제본을 활용한 고가용성(HA)을 제공한다. 따라서, 장애가 발생해도 클러스터 내 다른 복제본들이 동일한 데이터를 유지하고 있기에 서비스가 중단되지 않도록 설계되어 있다.

  1. 복구 실패 시 알림:
    만약 장애가 발생한 브로커가 오랜 시간 동안 복구되지 않는다면, 카프카는 관리 콘솔이나 설정된 알림을 통해 이를 관리자에게 통보한다. 이를 통해 관리자는 브로커를 수동으로 점검하고 조치를 취할 수 있다.

Kafka는 이러한 방식으로 장애 상황에서도 데이터 일관성을 유지하고, 서비스의 지속성을 보장하여 안정적인 메시징 서비스를 제공한다.

profile
알고리즘, 자료구조 블로그: https://gyun97.github.io/

0개의 댓글