메세지 큐와 브로커의 개념에 대해 잘 모르시는 분은 이전 포스팅인 MOM: 메세지 큐(Message Queue)와 브로커(Broker)을 정독하고 오시는 것을 권장합니다.
카프카(Apache Kafka) : 카프카는 대규모 실시간 데이터 스트리밍 및 이벤트 처리 시스템을 위한 분산형 메시징 시스템으로 여러 애플리케이션간에 데이터를 공유할 수 있게 하는 메시지 브로커 역할을 한다.
높은 처리량: kafka는 매우 높은 메시지 처리량을 자랑하기 때문에 대규모 데이터 스트리밍을 처리하는 데 적합하다.
확장성: kafka는 수평적으로 확장이 가능하여 클러스터에 브로커를 추가하여 처리 성능을 높일 수 있다.
데이터 영속성: kafka는 메시지를 디스크에 영속적으로 저장되며, 여러 복제본을 통해 내구성을 보장하기 때문에 데이터가 손실될 염려가 없다.
실시간 처리 : kafka는 실시간으로 데이터를 처리할 수 있어, 이벤트 기반 아키텍처에 적합하다.
분산 시스템: kafka는 분산 아키텍처로 설계되어 장애에 강하고, 데이터 손실 없이 메시지를 전달할 수 있다.
Producer
: 데이터를 kafka로 보내는 주체로 Producer는 데이터를 특정 토픽(Topic)에 담아 전송한다.
※ 전송 acks: Kafka의 acks(acknowledgments) 설정은 프로듀서(데이터를 보내는 쪽)가 메시지를 전송할 때 브로커가 어느 정도 수준의 확인 응답을 해야 전송을 성공했다고 간주할지를 설정하는 옵션이다.
acks 설정에 따라 데이터의 신뢰성과 지연 속도 간의 균형이 달라진다. 각 설정 값에 따라 메시지 전송 성공 여부가 결정되는 방식이 다르다.
Consumer
: Kafka에서 데이터를 소비하는 주체로 Consumer는 Kafka의 토픽에서 데이터를 읽어온다.
Broker
: Kafka 클러스터 내에서 데이터를 저장하고,Producer와 Consumer 간의 메시지를 중계하는 역할
을 하는 서버로 Kafka는 여러 개의 브로커로 구성된 클러스터로 동작할 수 있다.
Topic
: Kafka에서 데이터를 분류하는 논리적 단위이다. Producer는 메시지를 설정한 특정 토픽으로 전송하고, Broker는 토픽을 저장하며, Consumer가 해당 토픽을 구독하여 메시지를 가져온다.
Partition
: Kafka의 토픽은 여러 개의 파티션으로 나뉘어져 데이터를 분산 처리한다. 파티션은 메시지의 순서를 보장하고, 데이터를 병렬로 처리할 수 있도록 해준다.
데이터 중복 처리를 방지하기 위해 파티션은 한 컨슈머 그룹 내에서는 무조건 하나의 컨슈머하고만 연결되어야만 한다.
Zookeeper
: Kafka는 Zookeeper를 사용하여 Kafka 클러스터의 메타데이터를 관리하고, 브로커의 상태를 모니터링하며, 파티션의 리더 선출을 처리한다.
Consumer Group
: 하나 이상의 Consumer가 같은 Consumer Group으로 묶여 하나의 토픽을 병렬로 소비할 수 있도록 한다. 이 방식으로 메시지의 처리를 분산시키고, 각 메시지는 중복 없이 한 번만 소비되도록 할 수 있다.
Offset
: Offset는 카프카에서각 메시지가 파티션 내에서 저장되는 위치를 나타내는 고유한 번호이자 Consumer에서 메시지를 어디까지 읽었는지 저장하는데 활용되는 값
이다.
카프카는 메시지를 순차적으로 기록하고, 각 메시지에 대해 파티션 내에서 고유한 offset을 할당한다. 이 offset을 통해 카프카 클러스터 내의 파티션에서 메시지를 구별하고, 각 컨슈머에서 특정 파티션의 데이터를 어디까지 읽어 갔는지 기록할 수 있어 메시지를 정확히 찾아서 읽을 수 있게 한다.
Consumer에서 데이터를 잘 가져갔으면 offset을 브로커에 전달하고 그럼 브로커에서는 __consumer_offsets
라는 저장 공간에 각 컨슈머 그룹
에서 파티션 별로 어디까지 데이터를 가져갔는지 기록합니다.
offset을 통해서 컨슈머 그룹은 이전에 가져갔던 데이터를 다시 가져가는 중복 컨슘의 문제를 피할 수 있
다.
메시지 저장: Kafka 브로커는 메시지를 디스크에 저장한다. 메시지는 특정 토픽의 특정 파티션에 저장되어, Consumer가 요청할 때 메세지를 읽을 수 있다.
메시지 전달: Producer가 보낸 메시지를 저장하고, 이를 구독한 Consumer에게 전달하면 Consumer는 Kafka 브로커에서 데이터를 읽어온다.
메시지 복제: Kafka는 데이터를 여러 브로커에 복제하여 내구성을 보장한다. 이로 인해 각 파티션에 대해 복제본이 여러 개 존재할 수 있다.
여러 파티션을 사용함으로써 얻을 수 있는 주요 이점은 다음과 같다.
확장성(Scalability)
:
하나의 파티션만 사용할 경우, 해당 파티션에 대한 읽기 및 쓰기 요청은 단일 서버(혹은 브로커)에 집중되기 때문에 만약 데이터 양이 많아지면, 하나의 서버로는 처리하기 어려운 상황이 발생할 수 있다.
하지만 여러 파티션을 사용하면 데이터를 여러 서버에 분산시킬 수 있어, 데이터 양이 증가하더라도 시스템의 수평 확장이 가능해져 각 파티션이 독립적으로 운영되므로, 파티션 수를 늘리면 시스템 용량을 효율적으로 늘릴 수 있다.
병렬 처리 (Parallel Processing)
:
각 파티션은 독립적인 단위로 메시지를 저장하고 처리하므로, 여러 컨슈머가 동시에 각 파티션에서 메시지를 읽어가서 동시에 작업 진행이 가능해진다. 즉, 파티션 수가 많을수록 더 많은 병렬 처리가 가능해져 전체 서비스의 작업 속도를 향상시킬 수 있다.
예를 들어, 컨슈머 그룹에서 각 컨슈머가 하나의 파티션을 담당하면서 메시지를 병렬로 처리할 수 있다. 이로 인해 처리 속도가 빨라지고, 시스템이 더 많은 데이터를 빠르게 처리할 수 있다.
가용성 및 장애 대응 (Availability and Fault Tolerance)
:
카프카는 파티션 복제를 통해 장애 복구와 고가용성을 보장한다. 각 파티션은 여러 개의 브로커에 복제본을 두고 있어서, 특정 브로커가 장애를 일으켜도 해당 파티션의 데이터를 다른 브로커에서 제공할 수 있다.
복제된 파티션이 많을수록 시스템의 장애 대응 능력이 향상된다. 각 파티션이 다른 서버에 분산되어 있기 때문에, 데이터 손실을 최소화하고, 시스템의 가용성을 높일 수 있다.
부하 분산 (Load Balancing)
:
파티션을 여러 개로 나누면, 읽기/쓰기에 대한 부하를 여러 서버에 고르게 분배할 수 있다.
예를 들어, 쓰기 작업은 특정 파티션에만 집중되지만, 파티션 수가 많으면 각 서버로 분산되어 부하가 균등하게 나뉜다.
이로 인해, 서버 자원(CPU, 메모리 등)을 효율적으로 활용할 수 있다.
유연한 파티션 재배치 (Flexible Partition Rebalancing)
:
파티션 수를 늘리거나 줄일 수 있어 동적 확장에 유리하다. 시스템의 부하가 증가하면 새로운 파티션을 추가하여 처리량을 확장할 수 있고, 부하가 줄어들면 파티션을 조정하여 자원을 최적화할 수 있다.
카프카는 파티션 재배치(파티션의 리더와 복제본을 다른 브로커로 이동)를 통해 이러한 유연성을 제공한다.
효율적인 데이터 배포 (Efficient Data Distribution)
:
카프카는 메시지를 여러 파티션에 분배하여 효율적으로 데이터를 분산 저장하고, 각 파티션은 독립적인 로그로 저장된다. 이로 인해 대규모 데이터를 분산 처리하고 관리하는 데 유리하다.
결국 하나의 토픽을 여러 개의 파티션으로 나누는 이유는 카프카의 성능
, 확장성
, 병렬 처리
, 가용성
등을 최적화하기 위해서이다.
여러 파티션을 활용하면 데이터 양이 많아지더라도 시스템을 수평적으로 확장할 수 있고, 병렬 처리와 부하 분산을 통해 더 효율적으로 데이터를 처리할 수 있다. 또한, 파티션의 복제를 통해 고가용성 및 장애 복구가 가능해진다.
컨슈머 그룹(Consumer Group)은 카프카에서 매우 중요한 개념으로, 여러 개의 컨슈머(Consumer)가 하나의 그룹을 이루어 토픽에서 메시지를 병렬로 처리하도록 하는 방식입니다. 이를 사용하는 이유는 성능 향상, 부하 분산, 장애 복구 등 여러 가지 장점이 있기 때문입니다. 주요 이유는 다음과 같습니다:
부하 분산 (Load Balancing)
:
하나의 토픽에 여러 개의 컨슈머 그룹이 있다면, 각 컨슈머는 독립적으로 메시지를 처리하게 됩니다. 각 컨슈머는 그룹 내에서 하나의 파티션에만 메시지를 소비하게 되므로, 여러 컨슈머가 각각 다른 파티션을 처리하며 병렬로 작업을 분담합니다.
이로 인해, 하나의 컨슈머가 처리할 수 있는 데이터 양을 초과할 경우 여러 컨슈머가 각각 다른 파티션을 담당하여 부하를 분산시킬 수 있다.
병렬 처리 (Parallel Processing)
:
카프카에서 컨슈머 그룹을 사용하면, 여러 개의 컨슈머가 동일한 토픽을 처리하되, 각 컨슈머가 독립적인 파티션을 읽도록 함으로써 병렬 처리가 가능해진다.
예를 들어, 하나의 토픽에 4개의 파티션이 있고 4개의 컨슈머가 같은 컨슈머 그룹에 속하면, 각 컨슈머는 각 파티션에서 독립적으로 메시지를 읽어온다. 이를 통해 처리 속도를 대폭 향상시킬 수 있다.
메시지 처리의 효율성 (Message Processing Efficiency)
:
각 컨슈머가 하나의 파티션을 처리하기 때문에, 메시지의 순서 보장을 유지할 수 있다. 카프카는 파티션 단위로 메시지 순서를 보장하므로, 동일 파티션을 담당하는 컨슈머가 메시지를 처리하면 순서대로 메시지가 처리된다.
여러 컨슈머가 있을 경우 메시지 처리가 병렬로 이루어져 효율성이 극대화된다.
확장성 (Scalability)
:
카프카는 컨슈머 그룹을 통해 토픽에 대한 메시지 처리량을 수평적으로 확장할 수 있다. 예를 들어, 처음에는 2개의 컨슈머만 있을 때는 메시지가 두 개의 컨슈머에서만 소비되지만, 컨슈머 그룹에 새로운 컨슈머를 추가하면 파티션 수에 맞춰 자동으로 작업이 분배되어 성능이 향상된다.
파티션의 수에 맞춰 컨슈머 그룹에 컨슈머 수를 확장할 수 있어, 수요에 맞는 유연한 확장이 가능하다.
장애 복구 및 내결함성 (Fault Tolerance & Resilience)
:
카프카에서 컨슈머 그룹을 사용하면, 컨슈머 장애 시 다른 컨슈머가 대체하여 메시지를 소비할 수 있다. 예를 들어, 하나의 컨슈머가 장애로 중단되면, 같은 컨슈머 그룹에 속한 다른 컨슈머가 해당 파티션을 재배치 받아 메시지를 계속 처리할 수 있다.
이렇게 함으로써, 시스템의 장애 복구가 용이하고, 전체 시스템의 가용성을 높일 수 있다.
중복 메시지 처리 방지 (Message Deduplication)
:
컨슈머 그룹을 사용하면 각 파티션에 대한 메시지를 하나의 컨슈머만 읽을 수 있기 때문에, 중복 처리를 방지할 수 있다. 각 컨슈머는 자신에게 할당된 파티션에서만 메시지를 읽기 때문에, 다른 컨슈머가 이미 처리한 메시지를 중복해서 처리하는 일이 없다.
이를 통해 정확한 데이터 처리가 보장된다.
메시지의 공평한 분배 (Fair Message Distribution)
:
카프카는 파티션 수와 컨슈머 수에 맞게 메시지를 공평하게 분배한다. 각 파티션은 컨슈머 그룹 내에서 하나의 컨슈머에게만 할당되므로, 모든 컨슈머가 공평하게 메시지를 처리할 수 있다.
이로 인해, 하나의 컨슈머가 지나치게 많은 메시지를 처리하는 일이 없고, 전체 시스템의 부하를 고르게 분산시킬 수 있다.
단일 파티션에 대한 메시지 순서 보장 (Message Ordering Within a Partition)
:
카프카는 파티션 내에서 메시지 순서를 보장합니다. 컨슈머 그룹을 사용하면 각 컨슈머가 처리하는 파티션에서 메시지 순서를 보장하면서도, 여러 컨슈머가 동시에 다른 파티션을 처리하므로 순서 보장과 병렬 처리 두 가지를 동시에 만족할 수 있다.
예를 들어, 중요한 이벤트를 순차적으로 처리해야 하는 경우, 동일한 파티션에서 메시지를 처리하는 컨슈머를 통해 순서를 보장하면서도 병렬 처리의 이점을 취할 수 있다.
스케일링과 고가용성 (Scaling and High Availability)
:
컨슈머 그룹은 카프카의 고가용성과 수평 확장성을 지원한다. 컨슈머 그룹에 컨슈머를 추가하면, 더 많은 파티션을 처리할 수 있어 시스템의 성능과 처리 용량을 증가시킬 수 있다.
또한, 컨슈머 그룹은 장애가 발생했을 때 다른 컨슈머가 장애를 자동으로 대체할 수 있어 시스템의 고가용성을 유지할 수 있다.
결론적으로 카프카에서 컨슈머 그룹을 사용하는 이유는 부하 분산
, 병렬 처리
, 확장성
, 장애 복구
, 메시지 중복 방지
등을 통해 시스템의 성능과 안정성을 극대화하기 위해서이다.
특히, 대규모 분산 시스템에서 많은 데이터를 효율적으로 처리하고, 여러 개의 컨슈머가 협력하여 토픽에서 메시지를 처리하는 방식으로, 성능과 안정성을 크게 향상시킬 수 있다.
Kafka에서 특정 브로커가 장애를 일으키면 다음과 같은 단계로 복구 및 재분배가 이루어진다.
파티션 리더 이동:
장애가 발생한 브로커가 특정 파티션의 리더로 지정된 상태였다면, 주키퍼(ZooKeeper) 또는 카프카의 내부 컨트롤러가 자동으로 이 파티션의 리더 역할을 다른 팔로워 브로커로 이동시킨다. 팔로워 브로커 중 하나가 새 리더로 지정되어 클라이언트 요청을 계속 처리할 수 있게 한다.
장애 복구와 데이터 일관성 유지:
장애가 난 브로커가 복구되어 다시 클러스터에 참여하면, 카프카는 복제 데이터를 동기화하여 손실된 데이터가 없도록 한다. 이 과정에서 복제본의 오프셋 차이를 비교하고, 필요한 데이터를 새로 복제하여 동기화한다.
가용성 보장:
카프카는 기본적으로 복제본을 활용한 고가용성(HA)을 제공한다. 따라서, 장애가 발생해도 클러스터 내 다른 복제본들이 동일한 데이터를 유지하고 있기에 서비스가 중단되지 않도록 설계되어 있다.
Kafka는 이러한 방식으로 장애 상황에서도 데이터 일관성을 유지하고, 서비스의 지속성을 보장하여 안정적인 메시징 서비스를 제공한다.