Connecting

Apache Kafka 기본 본문

kafka

Apache Kafka 기본

팬도라 2020. 9. 22. 12:28
반응형

본 문서는 "실전 아파치 카프카", "카프카 데이터 플랫폼의 최강자" 책과 위키백과 등을 기반으로 작성되었음을 알려드립니다.

지난 시간에는 Apache Kafka (앞으로는 카프카로 지칭)의 대한 탄생배경과 목표, RabbitMQ과 어떠한 차이점을 가지고 있으며, 간단한 성능차이에 대해서 알아보았다. 이번 시간에는 카프카의 장점과 특징과 동작방식에 대해서 서술한다.

Kafka Basic

카프카는 기본적으로 대량의 메시지를 처리하기 위한 플랫폼이다. 다른 메시지 큐에 비해서 월등히 빠른 성능을 보여주고 전달하고자 하는 메시가 일부 중복이 발생하더라도 절대 메시지 손실이 발생하지 않는다는 원칙을 가지고 있다. 아래 표를 통해 메시지 전달 보증 수준을 확인해 보자.

종류 개요 재전송 유뮤 중복 삭제 유무 비고
At Most Once 1회 전달 시도 X X 메시지는 중복되지 않지만 손실될 수 있다.
At Least Once 적어도 1회 전달 O X 메시지가 중복될 수 있으나 손실되지 않는다.
Exactly Once 1회만 전달 O O 중복되거나 손실되지 않고 확실하게 메시지가 전달하나 성능이 떨어진다.

초기 카프카의 경우 성능을 중요시 했기 때문에 "At Least Once" 수준으로 전달을 보장하는 방식을 채택했다. 이를 실현하기 위해서 kafka ack offset commit 개념을 사용한다.

카프카에서 소비자에게 메시지를 전달했을때 이를 수신을 완료했다는 ACK를 전달하여 메시지 전달이 완료되었다고 알리게 되고, 만약 ACK가 도착하지 않으면 메시지를 다시 보내는 방식을 사용한다.

카프카에서는 오프셋이 존재하는데, 이를 통해 소비자가 메시지를 처리하다가 문제가 발생했을 경우에 재전송하더라도 문제가 발생한 시점부터 재전송을 진행하여 중복을 최소화 할 수 있다. 하지만 시간이 지남에 따라 정확하게 메시지는 전달하기 위한 "Exactly Once"의 요구가 발생하게 되어 카프카에서는 트랜젝션 기법을 통해 이를 지원하기 시작했다. "Exactly Once"가 실현되기 위해서는 생산자와 카프카, 카프카와 소비자 사이의 메시지 전달에 전반적인 관여가 필요하다.

카프카 특징

  1. 메시지를 파일시스템에 저장한다.

    • 기존 메시지 전달 시스템의 경우 메모리의 메시지를 적재하고 소비자가 메시지를 전달받으면 즉시 큐에서 삭제하지만 카프카의 경우 메시지를 파일 시스템에 저장하기 때문에 데이터 영속성이 보장되어 소비자가 원하는 경우 메시지를 다시 전달받을 수 있는 특징을 가지고 있다. 하지만 파일 시스템의 경우 용량이 유한하기 때문에 기본 보관 주기인 7일동안 메시지가 저장되며, 설정 변경을 통해서 주기를 늘리거나, 삭제 방식을 선택할 수 있다.
  2. 배치 전송 처리를 한다.

    • 서버와 클라이언트간의 데이터를 전송하는 경우 네트워크 I/O와 디스크 I/O 간의 오버헤드가 발생할 수 밖에 없는 구조를 가지고 있으나 카프카의 경우 크기가 작은 메시지를 그룹핑하여 한번에 전달하기 때문에 I/O 오버헤드로 인한 성능감소를 최소화 할 수 있다.
  3. *TCP Protocol를 사용한다. *

    • RabbitMQ가 AMQP 프로토콜을 기반으로 작성된 것과 다르게 TCP를 사용하여 프로토콜로 인한 오버헤드를 감소시킨다.
  4. *OS의 페이지 캐시를 사용한다. *

    • 버퍼 캐시는 최근 사용된 디스크 블록을 메모리에 캐시하는 것을 말한다. 도입 배경 디스크 입출력 시간이 메모리 접근 시간보다 크고, 디스크 블록의 접근 패턴에 지역성이 있기 때문에 디스크 블록의 정보를 메모리 공간에 저장해두면 읽기/쓰기 등의 작업시 응답시간을 줄일 수 있다.

    • 카프카는 이러한 특성을 고려하여 디자인 되었기 때문에 다른 메시지 큐에 비해서 빠른 처리속도를 보장할 수 있다.

  1. *시스템 확장이 용의하며 분산 시스템으로 단일 시스템보다 높은 성능을 얻을 수 있다. *

    • 카프카는 분산 시스템을 기반으로 만들어졌기 때문에 시스템 확장에 유리하도록 디자인 되었으며, 스케일에 따라서 시스템 확장이 유리하며 설정이 간편하다. 기본 3대로 클러스터를 구축하게 되며, 노드장애가 발생하면 다른 노드가 역할을 대신하기 때문에 HA 구성이 가능하다.

Kafka API Architecture

카프카는 다음 4가지 API를 통해 기본 시스템 구성을 가지고 있다. 각각의 API 특징을 간략하게 확인해 보도록 하겠다.

  1. Producer API

    • 애플리케이션이 카프카 토픽에 레코드 스트림을 게시할 수 있도록 한다.
    • 프로듀서는 이러한 API를 이용하여 브로커에게 데이터를 송신하기 위한 구현된 애플리케이션으로 실제 상황에서는 각종 로그 전송 및 미들웨어와 연동하여 동작한다.
  2. Comsumer API

    • 애플리케이션이 하나 이상의 토픽을 구독할 수 있으며, 애플리케이션이 해당 토픽에 생성된 스트림을 처리할 수 있도록 한다.
    • 이러한 API를 통해 컨슈머는 메시지를 취득하여 처리할 수 있는 애플리케이션 형태로 구현되며, 브로커는 메시지를 영속화하는 특징이 있기 때문에 컨슈머가 브로커로 부터 데이터를 즉시 수신받지 않는 상황에서도 디스크에 보관되어 있는 시점에는 메시지 취득이 가능하다.
  3. Streams API

    • 애플리케이션은 하나 이상의 주제에서 입력 스트림을 사용하고 스트림 작업으로 처리하고 출력 스트림을 생성하여 하나 이상의 주제로 보낼 수 있다.
    • 이러한 방식으로 Streams API를 사용하면 입력 스트림을 출력 스트림으로 변환하여 사용할 수 있다.
  4. Connect API

    • 생산자와 소비자의 실행을 구축 및 관리하고 애플리케이션 또는 데이터 시스템을 Kafka 주제에 연결할 수 있도록 하여 다른 통신방식을 사용하여 (REST API 등) 다른 응용 애플리케이션간의 통신을 지원한다.

Kafka Cluster Architecture

Kafka Brokers

카프카는 하나 이상의 서버 즉 브로커를 사용하여 구성된다. 생산자는 카프카 브로커의 토픽에 메시지를 push하며, 소비자는 카프카 토픽의 메시지를 pull 하여 메시지를 전달받는다. 각 브로커 인스턴스는 성능에 영향을주지 않고 초당 수십만 (및 테라 바이트의 메시지)에 이르는 읽기 및 쓰기 양을 처리 할 수 있고, 각 브로커에는 고유한 ID를 통해 토픽 로그 파티션을 담당 할 수 있다.

일반적으로 여러 브로커가 협력하여 Kafka 클러스터를 형성하고로드 밸런싱과 안정적인 중복성 및 장애 조치를 달성하며, 브로커는 클러스터의 관리 및 조정을 위해 Apache ZooKeeper를 사용한다. ZooKeeper는 브로커 및 토픽이 추가되거나 제거되는시기를 포함하여 Kafka 클러스터의 토폴로지가 변경되면 모든 노드에 알린다.

예를 들어, ZooKeeper는 새 브로커가 클러스터에 가입하거나 브로커에 오류가 발생하면 클러스터에 전송하며, 또한 ZooKeeper는 브로커와 토픽 파티션 쌍 사이에서 리더를 선택하여 특정 파티션 (및 생산자와 소비자의 서버 읽기 및 쓰기 작업)의 리더가 될 브로커와 동일한 데이터의 복제본을 보유하는 브로커를 결정할 수 있도록 한다. 브로커 클러스터가 변경되면 즉시 서로 조정을 시작하고 필요한 새 파티션 리더를 선택함으로서 브로커가 갑자기 문제가 발생하여 처리할 수 없는 상황에 대비할 수 있다.

만약 여러개의 Zookeeper를 통해 클러스터링을 하는 경우에는 3개 혹은 5개와 같이 홀수개로 구성하는 것이 좋다

아파치 주키퍼(Apache ZooKeeper)는 아파치 소프트웨어 재단 프로젝트중의 한 소프트웨어 프로젝트로서 공개 분산형 구성 서비스, 동기 서비스 및 대용량 분산 시스템을 위한 네이밍 레지스트리를 제공한다. 주키퍼는 하둡의 한 하위 프로젝트이었으나 지금은 독립적인 상위 프로젝트이다. 주키퍼의 아키텍처는 중복 서비스를 이용한 고가용성을 제공한다. 클라이언트는 주키퍼 마스터가 응답을 하지 않으면 다른 주키퍼 마스터에게 요청을 한다. 주키퍼 노드들은 파일 시스템이나 trie 데이터구조와 비슷한 구조의 네임 스페이스안에 데이터들을 저장한다. 클라이언트들은 이 노드들에게서 읽거나 쓴다.

Kafka Producers

  • Kafka 프로듀서는 하나 이상의 Kafka 주제에 대한 메시지를 최적화, 작성 및 전송하는 역할을 담당한다. 또한 브로커간에 데이터를 직렬화, 압축 및 LB 기능을 가지고 있다.

Kafka Consumers

  • 컨슈머는 구독하는 주제에서 메시지를 읽어 데이터 읽어서 처리할 수 있으며, 컨슈머 그룹에 속한다.

분산 메시징을 위한 구조

  • 토픽

    • 토픽은 데이터가 스트리밍되는 채널을 정의한다. 프로듀서는 토픽에 맞게 메시지를 게시하고 소비자는 구독하는 토픽에서 메시지를 읽을 수 있다.
    • 토픽은 카프카 클러스터 내에서 고유한 이름으로 식별되며 생성 할 수있는 토픽 수에는 제한이 없다.
  • 파티션

    • 메시지는 토픽으로 분류되고 이러한 토픽은 여러개의 파티션으로 나뉘어 질 수 있다. 이는 토픽에 대한 대량의 메시지를 지원하기 위해 데이터를 읽고 쓰는 과정은 파티션으로 분할되어 관리된다.
    • 각각의 파티션이 어디에 배치되는가의 대한 정보는 브로커가 가지고 있으며, 생산자와 소비자는 토픽을만을 지정하여 메시지를 전달받기 때문에 파티션에 대한 정보를 신경쓰지 않아도 된다.
  • 컨슈머 그룹

    • 카프카는 컨슈머에서 분산 스트림 처리를 고려하여 설계되어 있다. 단일 애플리케이션에서 여러 컨슈머가 단일 토픽이나 여러 파티션에서 데이터를 취득하기 위해 존대한다.
    • 카프카가 클러스터링으로 구성되어 있는 경우 여러 소비자가 단일 토픽 혹은 여러 파티션에서 메시지를 얻기 위해 그룹이 존재한다. 카프카는 전체 클러스터링에서 글로벌 ID를 소비자는 자식이 속한 그룹을 식별하여, 읽어들일 파티션을 분류하고 재시도 제어한다.
  • 오프셋

    • 각 파티션에서 수신한 메시지에는 각각 고유한 일련번호가 부여되어, 컨슈머가 취득하는 메시지의 위치를 파악하고, 이를 통해 메시지의 범위나 전송 실패가 발생했을 시 재시도를 문제가 발생한 부분부터 데이터를 읽어드릴 수 있다.
      • Log-End-Offset (LEO) : 파티션 데이터 끝을 나타낸다.
      • Current Offset : 컨슈머가 어디까지 메시지를 읽었는지 확인한다.
      • Commit Offset : 컨슈머가 어디까지 커밋했는지 나타낸다.

Kafka Architecture – Component Relationship Examples

카프카의 각각의 컨포넌트간의 관계를 이해하기 위해서 다음 사항을 숙지할 필요가 있다.

  1. 카프카 클러스터는 하나 이상의 브로커가 포함될 수 있다.

  2. 카프카 브로커는 여러 파티션을 가지고 있을 수 있다.

  3. 토픽은 하나 이상의 파티션을 포함할 수 있다.

  4. 각 파티션의 백업본은 서로 다른 브로커에 존재해야 한다. 단, 둘 이상의 브로커로 분할 백업될 수는 없다.


아래 그림은 프로듀서가 토픽에 해당하는 메시지를 전송하여, 토픽을 구독하고 있는 컨슈머에게 전송하는 그림을 확인할 수 있다.

여러 프로듀서가 각각의 토픽에 맞춰서 메시지를 전달하고, 혹은 하나 이상의 프로듀서가 하나의 토픽에 메시지를 전달하고자 한다면 다음과 같은 그림이 성립될 수 있다.

프로듀서 4, 5번은 같은 토픽에 대해 메시지를 전달하고 있으며, 컨슈머 3의 경우는 여러 토픽을 구독하여 메시지를 전달받는 것을 확인할 수 있다. 이를 통해 컨슈머는 자신이 원하는 메시지를 필터링하여 사용할 수 있음을 확인할 수 있다.

만약 비동기 방식으로 하나의 컨슈머가 다량의 토픽을 전달하면 어떻게 될까?

본래 우리가 알고있는 상식이라면, 프로듀서는 하나의 토픽에게만 메시지를 전달할 수 있으나 비동기 방식을 사용하면 필요에 따라 여러 토피의 해당하는 메시지를 전달할 수 있다. 단 카프카는 브로커의 성능과 확장성을 강조하기 때문에 컨슈머는 메시지를 수신하는 파티션을 제어해야 하는 의무를 가지게 된다.

Comments