티스토리 뷰

Kafka

[Kafka] 1. 카프카 기본 개념

mandykr 2023. 2. 1. 13:13

목차

1. 카프카

2. 주키퍼, 클러스터, 브로커

3. 프로듀서

4. 컨슈머

 

 

 

 

1. 카프카

 

카프카는 링크드인의 데이터팀이 파편화된 데이터 파이프라인의 복잡도를 낮추기 위해 개발한 오픈소스 프로젝트이다.

 

데이터 파이프라인
엔드 투 엔드 방식의 데이터 수집 및 적재를 개선하고 안정성을 추구하며, 유연하면서도 확장 가능하게 자동화한 것

 

높은 처리량

카프카는 프로듀서가 브로커로 데이터를 보낼 때와 컨슈머가 브로커로부터 데이터를 받을 때 많은 양의 데이터를 묶음 단위로 처리하기 때문에 네트워크 비용을 최소화할 수 있다.

또한, 파티션을 통해 데이터를 병렬 처리할 수 있어 시간당 데이터 처리량을 늘릴 수 있다.

 

확장성

카프카는 데이터가 적을 때는 클러스터의 브로커를 최소한의 개수로 운영하다가 데이터가 많아지면 브로커의 개수를 늘려 스케일 아웃할 수 있다. 반대로 데이터 개수가 적어지면 브로커 개수를 줄여 스케일 인할 수 있다.

 

영속성

카프카는 전송받은 데이터를 메모리가 아닌 파일 시스템에 적재하고 페이지 캐시 메모리 영역을 사용해 파일 시스템에 데이터를 저장, 전송하는 과정에서의 처리량을 높였다. 디스크 기반의 파일 시스템을 활용한 덕분에 브로커 애플리케이션이 장애 발생으로 종료되더라도 프로세스를 재시작하여 안전하게 데이터를 다시 처리할 수 있다.

 

고가용성

카프카 클러스터는 프로듀서에서 전송받은 데이터를 1대의 브로커에 저장하고 나머지 브로커에 복제된 데이터를 저장하기 때문에 한 브로커에 장애가 발생하더라도 지속적인 데이터 처리가 가능하다. 

 

2. 주키퍼, 클러스터, 브로커

 

1) 주키퍼

주키퍼는 카프카의 메타데이터를 관리하는 데 사용된다.

  • 통신 보안규칙, jmx port 상태 정보, host 정보
  • 컨트롤러 역할을 하는 브로커 정보
  • 카프카에 저장된 토픽 목록 정보

2) 클러스터, 브로커

브로커는 카프카 클라이언트와 데이터를 주고받기 위해 사용하는 주체이다.

카프카 클러스터로 묶인 브로커들은 프로듀서가 보낸 데이터를 안전하게 분산 저장하고 복제하는 역할을 수행한다.

 

(1) 데이터 저장, 전송

프로듀서로부터 데이터를 전달받으면 카프카 브로커는 프로듀서가 요청한 토픽의 파티션에 데이터를 저장하고 컨슈머가 데이터를 요청하면 파티션에 저장된 데이터를 전달한다.

 

프로듀서로부터 전달받은 데이터는 파일 시스템에 저장된다.

(토픽의 파티션이 11개이면 11개의 디렉토리가 생성된다.)

파일 시스템은 메모리에 올려서 사용하는 것보다 입출력 속도가 현저히 느리지만 카프카는 페이지 캐시를 사용하여 디스크 입출력 속도를 높였다.

 

(2) 데이터 복제, 싱크

토픽을 생성할 때 파티션의 복제 개수를 옵션으로 설정할 수 있다. (기본값은 브로커에 설정된 값)

복제를 통해 클러스터로 묶인 브로커 중 일부에 장애가 발생하더라도 데이터를 유실하지 않고 안전하게 사용할 수 있다.

 

복제는 파티션 단위로 이루어진다.

복제된 파티션은 리더와 팔로워로 구성된다.

팔로워 파티션들은 리더 파티션의 오프셋을 확인하여 현재 자신이 가지고 있는 오프셋과 차이가 나는 경우 리더 파티션으로부터 데이터를 가져와 자신의 파티션에 저장한다.

 

리더 파티션만 프로듀서, 컨슈머와 직접 통신한다.

리더 파티션이 저장된 브로커가 다운되면 리더 파티션은 사용할 수 없기 때문에 팔로워 파티션 중 하나가 리더 파티션 지위를 넘겨 받는다.

 

(3) 컨트롤러

클러스터의 브로커 중 한 대가 컨트롤러의 역할을 수행 한다.

컨트롤러는 다른 브로커들의 상태를 체크하고 장애로 브로커가 클러스터에서 빠지는 경우 리더 파티션을 재분배한다.

컨트롤러 역할을 하는 브로커에 장애가 생기면 다른 브로커가 컨트롤러 역할을 한다.

 

(4) 데이터 삭제

카프카는 컨슈머가 데이터를 가져가더라도 토픽의 데이터는 삭제되지 않고 오직 브로커만이 데이터를 삭제할 수 있다.

로그 세그먼트 단위로 삭제되는 데이터의 기한을 설정할 수 있고 오래된 데이터를 압축하는 정책을 가져갈 수도 있다.

 

(5) 컨슈머 오프셋 저장

컨슈머 그룹은 토픽이 특정 파티션으로부터 데이터를 가져가서 처리하고 이 파티션의 어느 레코드까지 가져갔는지 확이하기 위해 오프셋을 커밋한다.

커밋한 오프셋은 __consumer_offsets 토픽에 저장된다.

 

(6) 코디네이터

클러스터의 브로커중 한 대가 코디네이터의 역할을 수행한다.

코디네이터는 컨슈머 그룹의 상태를 체크하고 파티션을 컨슈머와 매칭되도록 분배하는 역할을 한다.

컨슈머가 컨슈머 그룹에서 빠지면 매칭되지 않은 파티션을 정상 동작하는 컨슈머로 할당하는 리밸런스 과정을 수행한다.

 

3) 토픽, 파티션

토픽은 카프카에서 데이터를 구분하기 위해 사용하는 단위이다.

토픽은 1개 이상의 파티션을 소유하고 있다.

파티션에는 프로듀서가 보낸 데이터인 레코드들이 저장된다.

 

파티션은 컨슈머들이 레코드를 병렬로 처리할 수 있도록 매칭된다.

 

3. 프로듀서

카프카 클라이언트를 라이브러리로 추가하여 프로듀서 애플리케이션을 만들 수 있다.

프로듀서는 카프카 브로커로 데이터를 전송할 때 내부적으로 파티셔너, 배치 생성 단계를 거친다.

 

1) ProducerRecord

전송하고자 하는 데이터는 ProducerRecord 클래스를 통해 인스턴스를 생성한다.

필수값인 토픽과 메시지 값을 설정하고 필요에 따라 파티션 번호, 타임스탬프, 메시지 키를 설정할 수 있다.

 

2) Partitioner

파티셔너는 ProducerRecord를 토픽의 어느 파티션으로 전송할 지 결정한다.

기본 파티셔너는 DefaultPartitioner 이고 프로듀서 API는 RoundRobinPartitioner, UniformStickyPartitioner를 제공한다.

Partitioner 인터페이스를 상속받은 사용자 정의 클래스를 만들 수 있다.

 

3) Accumulator

프로듀서는 파티셔너에 의해 구분된 레코드를 어큐뮬레이터에 버퍼로 쌓아놓고 배치로 묶어서 전송함으로써 처리량을 향상시킨다.

 

 

4. 컨슈머

카프카 클라이언트를 라이브러리로 추가하여 컨슈머 애플리케이션을 만들 수 있다.

컨슈머는 카프카 브로커에 적재된 데이터를 가져와서 필요한 처리를 한다.

 

1) Fetcher

컨슈머 애플리케이션을 실행하면 내부에서 Fetcher 인스턴스가 생성되어 컨슈머가 poll() 메서드를 호출하기 전에 미리 레코드들을 내부 큐로 가져온다.

이후에 사용자가 명시적으로 poll() 메서드를 호출하면 컨슈머는 내부 큐에 있는 레코드들을 받아 처리를 수행한다.

 

2) 컨슈머 그룹

컨슈머 그룹은 다른 컨슈커 그룹과 격리되는 특징을 가지고 있다.

따라서 프로듀서가 보낸 데이터를 각기 다른 역할을 하는 컨슈머 그룹끼리 영향을 받지 않게 처리할 수 있다.

예를 들어, 각기 다른 저장소에 저장하는 컨슈머를 다른 컨슈머 그룹으로 묶음으로써 각 저장소의 장애에 격리되어 운영할 수 있다.

 

컨슈머 그룹의 컨슈머 개수는 가져가고자 하는 토픽의 파티션 개수보다 작거나 같아야 한다.

3개의 파티션을 가진 토픽에서 4개의 컨슈머로 이루어진 컨슈머 그룹은 1개의 컨슈머가 파티션을 할당받지 못하고 유휴상태가 된다.

 

3) 컨슈머

데이터 처리중 발생한 리밸런싱에 대응하는 코드를 작성해야 한다.

파티션이 컨슈머에 재할당 되는 과정을 리밸런싱이라고 한다.
리밸런싱은 카프카 브로커중 한 대가 역할을 맡는 코디네이터에 의해 발생한다. 

다음 상황에서 리밸런싱이 발생한다.

  • 컨슈머가 추가되는 상황
  • 컨슈머가 제외되는 상황

리밸런싱으로 컨슈머의 가용성을 높일 수 있지만 리밸런싱이 발생할 때 파티션의 소유권을 재할당 하는 과정에서 데이터의 중복이나 유실이 발생할 수 있다.

따라서 컨슈머는 브로커로부터 데이터를 어디까지 가져갔는지 커밋을 통해 기록해야 한다.

커밋은 브로커의 내부 토픽(__consumer_offsets)에 기록된다.

 

명시적 오프셋 커밋

  • poll() 메서드 호출 후 일정 간격마다 자동으로 커밋
  • poll() 메서드 호출 이후에 리밸런싱 또는 강제 종료 시 데이터 중복 또는 유실 발생 가능

 

비명시적 오프셋 커밋

  • 동기 오프셋 커밋
    • commitSync() 사용
    • 브로커에 커밋 요청을 하고 응답을 기다린다.
    • 컨슈머의 처리량에 영향을 미침
  • 비동기 오프셋 커밋
    • commitAsync() 사용
    • 브로커에 커밋 요청을 하고 응답을 기다리지 않는다.
    • 커밋 요청이 실패한 경우 현재 처리중인 데이터의 순서를 보장하지 않으며 데이터 중복 처리가 발생할 수 있다.

 

 

 

 

 

 

참고

아파치 카프카 애플리케이션 프로그래밍

 

 

728x90

'Kafka' 카테고리의 다른 글

[Kafka] 5. 스키마 레지스트리  (0) 2023.04.18
[Kafka] Spring Kafka 구성(Broker, Producer, Consumer)  (0) 2023.03.21
[Kafka] 4. 카프카 컨슈머  (0) 2023.02.02
[Kafka] 3. 카프카 프로듀서  (0) 2023.02.02
[Kafka] 2. 토픽과 파티션  (0) 2023.02.02