Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>
 Kafka Logo

Contents

Apache Kafka

카프카(kafka)는 분산 스트리밍 플랫폼(Distributed streaming platform)이다. 분산 스트리밍 플랫폼은 아래의 기능을 가지고 있어야 한다.
  1. 데이터 스트림을 게시(Publish)하고 구독(Subscribe)할 수 있어야 한다. 이 점에서 메시지 큐 혹은 엔터프라이즈 메시징 시스템과 유사한 면이 있다.
  2. 내결함성(장애에 대한 내성)을 가지고 있어야 한다. 스트리밍 플랫폼을 구성하는 노드에 문제가 생기더라도 데이터를 안전하게 저장 할 수 있어야 한다.
  3. 데이터 스트림을 처리 할 수 있어야 한다.
카프카는 분산 스트리밍 플랫폼이 가져야 하는 위의 기본적인 기능을 가지고 있다. 카프카는 아래의 응용프로그램을 개발하는데 유용하게 사용 할 수 있다.
  1. 시스템과 시스템 혹은 시스템과 애플리케이션 사이에 안전한 데이터 전송을 위한 실시간 스트리밍 데이터 파이프라인 구축
  2. 데이터 스트림을 변환하거나 이를 받아서 즉시 처리하는 실시간 스트리밍 애플리케이션의 구축
카프카가 어떻게 이런일을 하는지 살펴보자. 아래 카프카의 주요 컨셉을 설명하고 있다.
  • 카프카는 하나 이상의 서버로 구성되는 클러스터에서 작동한다.
  • 카프카 클러스터는 토픽(topics)라고 부르는 파이프라인에 데이터 레코드 스트림을 저장한다.
  • 각각의 레코드는 키, 값, 타임스탬프로 구성된다.
카프카의 주요 API들은 아래와 같다.
  • Producer API : 애플리케이션은 이 API를 이용해서 하나 이상의 카프카 토픽에 스트림 레코드를 게시할 수 있다.
  • Consumer API : 애플리케이션은 이 API를 이용해서 하나 이상의 카프카 토픽으로 부터 스트림 레코드를 구독 할 수 있다.
  • Streams API : 애플리케이션이 하나 이상의 토픽에서 입력 스트림을 읽고 변환해서 하나 이상의 출력 토픽으로 스트림을 보낼 수 있도록 한다.
  • Connector API : Connector를 이용해서 재 사용 가능한 Producer 혹은 Consumers를 카프카 토픽에 연결 할 수 있다. 예를 들어 관계형 데이터베이스 컨넥터는 테이블에 대한 변경 사항을 캡처할 수 있다.
아래 그림은 카프카의 구성요소들을 보여주고 있다. 이들 구성요소들은 위의 주요 API를 이용해서 주어진 일을 한다.

토픽(Topics)과 로그(Logs)

카프카가 제공하는 핵심 기능인 토픽을 이용한 레코드의 스트리밍에 대해서 살펴보자.

토픽은 게시하고자 하는 레코드에 대한 카테고리 혹은 피드의 이름이다. 카프카에서는 하나의 토픽에 여러 구독자가 붙을 수 있다. 즉 하나의 토픽에 0, 1 혹은 두 개 이상의 구독자가 붙을 수 있다. 그리고 카프카 클러스터는 각 주제를 관리하기 위해서 아래와 같은 파티션로그를 유지한다.

 카프카 log 구조

카프카 클러스터는 토픽을 여러 노드에 분산된 파티션에 분산해서 저장한다. 각 파티션은 추가되는 레코드를 순서대로 계속 쌓으며 이에 대한 커밋 로그를 가지고 있다. 그리고 각 레코드를 식별하기 위한 일련번호(ID)가 할당된다. 아래 그림을 보자.

카프카 클러스터는 파티션에 개시된 모든 레코드를 설정한 기간동안 보존을 한다. 예를 들어 보존 정책을 2일로 설정했다면, 해당 레코드는 게시를 한 이틀동안 계속 남아있다. 보존기간이 지나면 공간을 절약하기 위해서 삭제한다. 카프카는 데이터의 크기와 상관없이 일정한 성능을 유지하도록 설계됐으므로 오랫동안 데이터를 저장하는 것이 문제되지 않는다.

컨슈머들은 로그에서 어디까지를 읽었는지에 대한 정보(offset)만을 저장한다. 이 offset은 컨슈머가 직접 조작하므로 능동적으로 그리고 순차적으로 메시지를 읽을 수 있다. 일반적으로는 순차적으로 메시지를 읽겠지만 필요하다면 과거로 offset을 재 설정할 수도 있다.

컨슈머는 로그에서의 위치정보만 가지는 것으로 메시지를 읽을 수 있으므로 매우 가볍게 만들 수 있다.

분산

로그의 파티션은 카프카 클러스터가 관리하는 노드들에 분산이 된다. 아래 그림을 보자.

 파티션의 분산

이렇게 파티션이 여러 노드에 분산이 되면, 프로듀서는 이들 중 하나의 파티션으로 메시지를 전송한다. 메시지 전송 알고리즘은 라운드로빈을 사용 할 수도 있고, 직접 구현한 알고리즘을 사용 할 수도 있다. 알고리즘에 따라서 메시지의 순서가 바뀔 수 있으므로, 메시지 순서가 중요한 서비스라면 대비책을 준비해야 한다.

복제

Kafaka는 파티션을 여러 벌 복사하는 방식으로 장애에 대응한다. 예를 들어 2개의 복제를 만든다면 아래와 같이 구성된다.

 파티션의 복제

파티션 P0, P1, P2는 브로커로 분산된다. 그리고 각 파티션의 복제인 R1, R2도 노드에 분산된다. 따라서 하나의 노드에 문제가 생기더라도 다른 노드의 파티션을 이용해서 메시지를 주고 받을 수 있다. 복제는 마스터-슬레이브방식으로 운영된다. 파티션 P0을 보자. P0-L이 리더가 되고 P0-R1, P0-R2는 팔로어가 된다. 메시지에 대한 읽기쓰기는 리더만이 수행한다.

컨슈머와 컨슈머 그룹

메시지 큐는 보통 큐(queue)발행/구독(Pub/Sub) 두 가지 모델을 지원한다. 큐 모델 에서 특정 메시지는 하나의 인스턴스에서만 꺼내갈 수 있지만, 발행/구독 모델에서는 특정 메시지를 하나 이상의 인스턴스에서 꺼내갈 수 있다.

예를 들어 유저의 API를 처리하는 REST API 서버라면 한번의 모델을 써야 할 것이다. 하지만 실시간 분석이 필요로 하는 서비스라면, 하나의 메시지를 메시지를 저장하는 인스턴스와 메시지를 분석하는 인스턴스(spark 같은)이 동시에 꺼내가야 할 것이다.

Kafka는 컨슈머 그룹이라는 개념을 도입해서 큐와 발행/구독 모델을 모두 지원한다. 아래의 그림을 보자.

 컨슈머 그룹

컨슈머 그룹은 메시지를 처리하기 위한 애플리케이션의 그룹이다. 예를 들어 빌딩의 센서로 부터 발생하는 메시지를 처리하는 서비스를 만든다고 가정해보자. 메시지의 향후 분석을 위해서 저장하는 소프트웨어가 필요한가 하면, 실시간으로 메시지를 분석해서 처리하는 소프트웨어도 필요 할 것이다. 이들 각각의 소프트웨어 그룹이 컨슈머 그룹이다.

이렇게 컨슈머 그룹을 두 개이상 붙이는 것으로 PUB/SUB 모델을 구현할 수 있다. 만약 하나의 컨슈머 그룹이 붙는다면, 큐 모델이 된다.

메시지에 대한 보증

카프카는 아래와 같은 방법으로 메시지를 보증한다.
  • 프로듀서가 특정 파티션으로 보낸 메시지는 전송된 순서대로 추가도니다. 즉 메시지 M-1과 메시지 M-2가 동일한 프로듀서가 보낸 다고 할 때, M-1을 M-2 보다 먼저 보내면 M-1이 더 낮은 오프셋을 기잔다. 메시지 순서가 중요한 애플리케이션이라면, 순서를 지켜야하는 메시지가 동일한 프로듀서가 처리 하도록 시스템을 구성해야 한다. 예컨데, 채팅 애플리케이션의 경우 한 유저는 반드시 하나의 프로듀서가 메시지를 처리해야 한다.
  • 컨슈머는 로그에 저장된 순서대로 레코드를 읽어온다.
  • N개의 복제가 있을 경우, 최대 N-1개의 서버 오류에 대해서 레코드를 잃어버리지 않는다.

스토리지 시스템

카프카는 디스크로 메시지를 저장하며, 내결함을 위해서 N 개의 복제를 만든다. 따라서 그 자체로 효율적인 스토리지 시스템으로 사용이 가능하다. 데이터가 디스크에 저장되기 때문에, 안전하게 persistent 하게 저장을 할 수 있으며 또한 클라이언트는 저장된 데이터의 위치를 제어 할 수 있기 때문에 고성능, 짧은 지연을 가져야 하는 커밋 로그 스토리지 등의 특수한 스토리지 시스템으로 응용 할 수 있다.

스트림 프로세싱

단지 데이터를 읽고 쓰는 스토리지 시스템만으로는 충분하지 않다. 카프카는 실시간을 데이터 처리 목적으로 사용 할 수 있다. 카프카의 스트림 프로세서는 입력 토픽에서 연속적인 데이터 스트림을 읽어서 처리하고 그 결과를 다시 토픽 스트림으로 출력 할 수 있다.

예를 들어 소매 응용 프로그램은 판매 및 출하 토픽으로 부터 입력 스트림을 받아서, 다양한 계산을 한 후에 재주문 및 가격 조정 스트림으로 다시 보낼 수 있다. 이 과정은 프로듀서 API와 컨슈머 API로 수행 할 수도 있다. 하지만 카프카의 스트림 API를 이용하면, 복잡한 처리를 쉽게 수행 할 수 있다. Introducing kafka streams 문서를 읽어보자.

참고