아파치 카프카는 실시간 스트리밍 데이터 처리를 하는 데에 있어
가장 주목받는 프레임워크이자 오픈소스 도구이다
아파치 카프카(Apache Kafka)는 미국의 대표적인 비즈니스 SNS인 링크드인(LinkedIn)에서 처음 개발된 분산 메시징 시스템이다. 간단히 말해 실시간으로 데이터를 수집하고 처리하는 데 최적화된 시스템이다!✨
데이터를 생성해서 무사히 저장하기까지 일련의 과정을 데이터 파이프라인이라고 하는데, 카프카는 현재 데이터 파이프라인을 구축할 때 가장 많이 고려되는 시스템이다. 아파치 카프카는 이벤트 스트리밍뿐만 아니라, 빅데이터 아키텍처에 있어서 중요한 역할을 하는 만큼, 카프카가 사라진다면 대용량·대규모 데이터 처리 관련 기업은 모조리 무너진다 해도 과언이 아닐 것이다.
이렇게 우리에게 꼭 필요한 Kafka에 관해 등장 배경부터 개념과 동작방식, 장단점까지 알아보도록 하자 :>
카프카가 없던 초기 링크드인은 데이터 수집 및 분배를 처리하기 위해 데이터를 생성하는 source application과 데이터가 최종 적재되는 target application을 단방향 end-to-end로 연결했다.
시간이 지날수록 애플리케이션의 개수가 늘어나고 데이터 전송 파이프라인이 늘어나기 시작하면서 아키텍쳐가 복잡해졌다. 단방향 연결을 end-to-end로 모두 잇다 보니 다음 그림과 같이 매우 복잡한 구조가 되었고, 그 복잡도는 점차 상승했다.

이는 서비스를 운영하는 데 치명적이므로 링크드인 데이터팀은 다양한 데이터 프레임워크와 오픈소스를 아키텍쳐에 녹여내어 개선하기 시작했지만, 데이터 파이프라인의 복잡도를 개선하기엔 부족했다.
따라서 링크드인에서 최초로 배치성 데이터와 실시간 이벤트 스트리밍 데이터를 혼합하여 처리하는 독특한 로직의 플랫폼을 만들어 냈는데, 그것이 Kafka(카프카)의 탄생이다!✨

: 실시간으로 데이터를 스트림 파이프라인을 통해 관리하기 위한 오픈소스 분산형 데이터 스트리밍 플랫폼
카프카는 분산 스트리밍 플랫폼으로, 끊임없이 들어오는 데이터를 실시간으로 처리하거나 가공하여 타 서비스에 제공한다. 이는 사용자의 홈페이지 클릭 수, 특정 상품을 바라보는 빈도 및 시간, 주문 및 환불 서비스 등 어플리케이션 사용자의 활동 분석을 통해 기업에서 전략적으로 비즈니스를 할 수 있도록 데이터를 수집/분석한다.
카프카는 비즈니스 전략을 위해 (링크드인 뿐만 아니라) 넷플릭스, 트위터, 오라클 등에서 사용 중이다.
→ Kafka는 단순히 데이터를 저장하고 전달하는 것으로 끝이 아니라, 데이터에 대한 메타 데이터도 제공함으로써 비즈니스 전략에 큰 역할을 한다는 것이다! 😎👍
Publish-Subscribe 모델은 데이터를 만들어내는 Publisher(Producer, 생산자), 소비하는 Subscriber(Consumer, 소비자) 그리고 이 둘 사이에서 중재자 역할을 하는 Broker로 구성된 느슨한 결합의 시스템이다.
이러한 느슨한 결합을 통해 Publisher나 Subscriber가 죽을 시, 서로 간에 의존성이 없으므로 안정적으로 데이터를 처리할 수 있다. 또한 설정 역시 간단하게 할 수 있다는 장점이 있다.
또, 이 모델은 topic에 입력된 데이터를 여러 consumer가 서로 다른 처리를 하기 위해 여러 번 가져올 수 있는 데이터 분포 모델이다. consumer가 broker로부터 메시지를 직접 가져가는 pull방식(=polling 구조)으로 동작하기 때문에 consumer는 자신의 처리 능력만큼의 메시지만 가져와 최적의 성능을 낼 수 있다. 이는 대용량 처리에 특화되어 있다고 할 수 있다.
카프카의 구조를 알아보면서 각 구성 요소와 역할도 알아보자.

💡 우선 개괄적인 이미지를 그려보자면, 카프카를 사용하는 시스템은 크게 세 가지의 구조로 이루어진다. Producer, Kafka Cluster, Consumer이다.
처리해야 하는 데이터를 쌓아두고 있는 데이터 저장소라고 생각하면 된다. 프로듀서가 처리해야 하는 이벤트를 넣어주면 카프카 클러스터가 보관, 컨슈머가 순차적으로 처리한다.
Kafka Cluster는 이벤트를 Topic : 토픽이라는 개념으로 구성한다. 토픽은 주제별로 관련된 이벤트를 모으는 단위 즉, 이벤트를 분류하는 단위이다.
카프카는 처리해야 하는 데이터를 토픽 단위로 분류하기 때문에 프로듀서와 컨슈머는 하나의 카프카 클러스터 안에서 각자의 관심사를 분류할 수 있는 것이다.
토픽은 한 개 이상의 Partition (파티션)으로 구성된다.
이벤트가 토픽에 들어오면 뒤에 append 형식으로 파티션이 추가되며, offset을 할당받게 되어 이 offset이 메시지를 식별할 수 있는 유니크한 값이 된다. 이 offset을 기준으로 데이터는 순차적으로 컨슈머에 의해 처리된다.
🔎 하나의 Topic에 여러 개의 Partition을 나눠서 메시지를 쓰는 이유?
메시지가 카프카의 해당 토픽에 쓰일 때, 쓰는 과정도 시간이 소비된다. 몇천 건의 메시지가 동시에 Kafka에 쓰여질 때 하다의 파티션만 있다면, 메시지가 하나의 파티션에 순차적으로 추가될 텐데, 처리하는 데 오래 걸리고 버거워진다. 따라서 여러 개의 파티션을 두어서 분산저장을 하는 것이다. 그러면 쓰는 작업이 병렬로 처리되기 때문에 시간이 그만큼 절약된다. 하지만, 한번 늘린 파티션은 절대로 줄일 수 없기 때문에 운영 중에 파티션을 늘리는 작업은 매우 신중히 해야 한다!
프로듀서는 처리해야 하는 일을 produce : 생산하는 생산자 역할이다. 처리해야 할 일을 카프카 클러스터로 보내어 차곡차곡 쌓아두도록 하는 것이다.

producer를 통해 전달되는 메시지의 구조
메시지 전달 과정
1. 직렬화 (Serializer)
2. 파티셔닝 (Partitioner)
3. 메시지 배치 (Record Accumulator)
4. 압축 (Compression)
5. 전달 (Sender)

컨슈머는 읽어온 데이터의 오프셋을 기록하여 자체적으로 읽은 데이터의 위치를 추적한다.
이를 통해, 컨슈머는 중단된 시점부터 데이터를 다시 읽거나 특정 범위의 데이터만을 읽어올 수 있다.
💡 Kafka consumer는 더욱 효율적이고 유연한 메시지 구독을 위해 3가지 특징을 가지고 있다!
일반적으로 다른 메시지 큐는 메시지를 Push하는 방식이다. 이러한 Push 방식의 가장 큰 단점은 메시지 큐가 consumer로 메시지를 push할 때 consumer의 환경, 처리 능력을 고려해야 한다는 것이다. Kafka는 이러한 단점을 보완한 Polling 구조로 설계되었다. Polling 구조는 consumer가 자신이 원하는 만큼의 메시지를 broker로 요청하는 구조이다. 이로써 각 consumer가 자신의 환경에 메시지 구독 성능을 최적화할 수 있으며, 추가로 broker는 더이상 consumer의 환경을 고려할 필요가 없다.
하나의 토픽에 대해 여러 consumer가 구독할 수 있다. 단일 토픽에 대해 멀티 컨슈밍이 가능한 이유는 consumer가 메시지를 읽을 때 broker의 메시지가 삭제되는 것이 아니고, 각 consumer가 어느 토픽 파티션의 어느 오프셋까지 읽어갔는지 consumer offset이라는 토픽에 저장되기 때문에 독립적으로 구독할 수 있다.
Kafka consumer는 하나 이상의 consumer가 consumer group을 구성하여 하나의 토픽을 구독할 수 있다. consumer group은 하나의 topic에 대한 책임을 가지며, 각 consumer는 topic의 partition에 대해 소유권을 가지고 구독한다.
💡 이는 특정 파티션을 하나의 컨슈머로만 처리할 경우 발생하는 문제를 방지한다! :>
어떤 그룹 내의 한 컨슈머가 다운되는 상황을 예로 들면, 다운된 컨슈머에 대해 rebalabce (가용한 컨슈머 사이에서 파티션을 재조정하는 작업) 가 일어난다. offset 정보를 그룹 내에서 공유하기에, 다른 컨슈머가 다운된 컨슈머의 역할을 대신해서 다운 직전의 offset 위치를 알고 그 다음부터 소비를 진행할 수 있다!✨
개괄적으로 그려본 이미지에서는 처리해야 하는 데이터를 쌓아두고 관리하는 곳을 Kafka Cluster라고 묶어 얘기했으나, 실질적으로 카프카 클러스터는 크게 Zookeeper와 Broker로 이루어져 있다.
카프카의 Broker는 실제 데이터가 저장되는 저장소 역할을 하며, 카프카의 Zookeeper는 카프카의 구성정보와 상태를 관리하는 관리자 역할을 하는 것이다! :>

Broker는 데이터의 저장과 전달을 관리하며, Producer로부터 전송된 데이터를 Topic에 저장하고, Consumer에게 필요한 데이터를 제공한다. 실질적으로 데이터를 관리하는 역할인 셈이다. Cluster는 여러 대의 Broker로 구성되고, 각 브로커는 데이터의 Partition을 관리하며 데이터의 복제와 장애 조치 기능을 수행한다.
💡 그런데, 언제나 하나의 "군집"이 있으면 군집이 안정적으로 유지되도록 통제하는 "리더"가 필요하기 마련이다! 따라서 Kafka의 Broker 사이에서도 리더가 정해지며, 리더 브로커는 컨트롤러라고 부른다. 😎
🔎 컨트롤러는 무슨 일을 할까?
- 한 클러스터에서 하나의 Broker에 부여되는 역할로, 마치 지휘자와 같은 역할
- 컨트롤러는 나머지 Broker들의 생존 여부(liveness)를 체크
- 만약 임의의 Broker가 중단되었을 경우, 해당 Broker에 있었던 리더 파티션을 탈락시키고 다른 팔로워 파티션들 중 하나를 리더로 뽑음(leader selection).
- 컨트롤러가 중단되는 경우에는 주키퍼가 이를 감지하여 새로운 컨트롤러를 선출 (이 과정은 cunsuming의 fail-over(실패 극복) 전략 중 중요한 부분이다.)
Zookeeper는 클러스터의 구성정보와 상태를 관리하는 분산형상관리도구이다. 이는 카프카 클러스터의 구성, 토픽의 메타 데이터, 브로커의 상태, 컨슈머 그룹 등을 추적하고 유지한다. 카프카의 주키퍼는 브로커들 간의 리더 산출, 동기화, 이벤트 처리 등 분산 시스템 작업을 도맡아 수행하며, Broker의 추가/제거 및 Topic의 생성/삭제와 같은 클러스터의 구성 변경도 관리한다. 이로써 주키퍼는 클러스터의 안정성과 일관성을 보장해 준다.
🔎 주키퍼? 주키퍼의 명확한 개념!
주키퍼(ZooKeeper)는 Apache Software Foundation에서 개발한 분산 시스템 애플리케이션을 위한 오픈 소스 서비스 프레임워크이다. 주키퍼는 분산 환경에서 데이터를 저장하고 처리하기 위한 서버 측 소프트웨어이다. 이러한 데이터는 분산 시스템에 대한 메타 데이터, 상태 정보, 구성 정보 등을 저장하는 데 사용된다.
주키퍼는 대규모 분산 환경에서 안정적인 운영을 위한 다양한 기능을 제공한다. 예를 들어, 주키퍼는 분산 환경에서의 데이터 일관성을 보장하고, 분산 시스템 내의 노드 상태를 모니터링하며, 분산 시스템의 구성 관리와 설정 변경 등을 수행한다.
또한, 주키퍼는 클러스터를 구성하고 관리하기 위한 리더 선출, 서버 장애 복구 및 복제와 같은 기능도 제공한다. 이러한 기능들은 분산 시스템에서 발생하는 여러 문제를 해결하기 위한 중요한 역할을 한다.
주키퍼는 다양한 분산 시스템에서 사용되며, 특히 아파치 카프카에서 메타 데이터와 브로커 정보를 저장하기 위해 사용된다.
카프카는 프로듀서가 브로커로 데이터를 보낼 때와 컨슈머가 브로커로부터 데이터를 받을 때 모두 많은 양의 데이터를 묶어서 전송한다. 데이터 처리 방식 또한 묶음 단위로 처리하는 데에 적합하기에 높은 처리량을 보인다. 이는 동일한 양의 데이터를 보낼 때 네트워크 통신 횟수를 줄일 수 있으므로 네트워크 비용 면에서도 장점이 된다.
묶어서 이동된 데이터를 처리할 때에는, 파티션 단위를 통해 동일 목적의 데이터를 여러 파티션에 분배하고 데이터를 병렬 처리할 수 있으므로 시간 당 데이터 처리량도 비교적 많다.
카프카는 가변적인 환경에서 수평적 확장이 안정적으로 가능하도록 설계되어 scale-out과 scale-in이 자유롭다. 이로써 처리해야 하는 데이터가 갑자기 비정상적으로 증가하더라도 다른 플랫폼에 비해 고성능을 자랑한다.
Kafka는 데이터 복제가 중요하다. 카프카를 장애 허용 시스템으로 동작하도록 하는 원동력이 된다. 복제의 이유는 브로커 중 일부에 장애가 발생하더라도 데이터를 유실하지 않고 안전하게 사용하도록 하기 위함이다.
Kafka cluster 위에서 producer가 전송한 메시지는 중복 저장이 된다. 토픽 내에서 생성된 파티션의 복제본을 Replication이라 칭한다. 복제된 파티션은 리더(leader)와 팔로워(follower)로 구성된다. 프로듀서 또는 컨슈머와 직접 통신하는 파티션을 리더, 나머지를 팔로워라고 한다.
팔로워 파티션은 리더 파티션의 오프셋을 확인하여 현재 자신이 가지고 있는 오프셋과 차이가 나는 경우 리더 파티션으로부터 데이터를 가져와 자신의 파티션에 저장한다. 클라이언트(producer, consumer)가 read/write 작업을 원할 때 작업을 수행하는 건 오로지 leader의 역할이다. 나머지 follower들은 leader와 싱크를 항상 맞추다가 혹시나 leader가 죽었을 경우, 나머지 follower 중에 하나가 leader로 선출되어서 leader의 역할을 수행한다.
→ 이렇게 장애가 발생하더라도 partition 단위로 fail over가 수행되므로 Kafka는 가용성이 높다는 것을 장점으로 가진다! :>
복잡도가 있어 일정 수준의 기술적인 이해가 있어야 안전한 세팅이 가능하며, 기본적으로 다수의 브로커를 요구하기에 많은 서버 비용이 요구된다.
📝 정리하기
아파치 카프카 Apache Kafka는 초기 링크드인의 복잡함을 해결하기 위해 탄생한 분산형 데이터 스트리밍 플랫폼이다. 이는 Producer - Kafka Cluster - Consumer의 구조로, 시스템 간의 방대한 데이터의 이동을 중앙에서 관리할 수 있다. 많은 양의 데이터를 묶어서 전송, 파티션 단위를 사용해 처리, 수평적 확장이 가능하여 고성능을 자랑하고, 데이터를 복제해 partition 단위로 fail over를 수행하여 고가용성을 띠는 것이 Kafka의 대표적인 장점이다! :>