티스토리 뷰

공부/Apache Kafka

Kafka 기본 개념

JStack 2024. 4. 17. 23:09

카프카를 구성하는 주체

카프카 브로커는 데이터를 분산 저장하며 클라이언트와 데이터를 주고 받는 주체이다.

하나의 서버 인스턴스에 하나의 카프카 브로커 프로세스를 실행하며, 여러 카프카 브로커를 묶어 클러스터를 구성하여 사용할 수도 있다.

클러스터로 사용하게되면 데이터를 분산 저장하며 복제하여 고가용성을 달성한다.

출처: https://wiki.terzeron.com/ko/OS_일반_시스템/Kafka/Kafka_소개

 

카프카 브로커는 프로듀서로부터 데이터를 전달받아 토픽의 파티션에 저장한다.

그리고 컨슈머가 데이터를 요청하게되면 파티션에 저장된 데이터를 전달한다.

 

데이터를 저장하고 전송하는 방법

카프카 브로커가 프로듀서에게 전달받은 데이터는 파일 시스템에 저장된다. 이 때 저장되는 위치는 server.properties 파일 내의 log.dir 옵션에 설정된 디렉토리이다.

전달받은 데이터가 저장되는 위치

위와 같이 데이터가 저장된 디렉토리에 접근해서 확인하면 각 토픽+파티션별 디렉토리가 생성되어 관리된다.

 

카프카는 이와 같이 메모리, 데이터베이스, 캐시 메모리 대신 파일 시스템을 사용하여 데이터를 관리한다.

일반적으로 파일 시스템은 IO가 많이 발생할 수록 성능 저하가 발생할 수 있으나, 카프카는 페이지 캐시를 사용하여 디스크 입출력 속도를 높여서 문제를 해결했다.

페이지 캐시란 OS 레벨에서 메모리 영역에 만들어놓은 캐시 공간이다. 한 번 읽은 데이터는 페이지 캐시에 저장해두어, 두 번째 조회 시에는 디스크를 읽지 않고 메모리를 읽어 성능을 향상시켰다.

 

데이터 복제와 싱크

카프카는 데이터를 복제하기 때문에 장애 허용 시스템으로 동작한다.

특정 브로커에 장애가 발생하더라도 데이터를 유실하지 않고 안전하게 사용할 수 있다.

 

카프카는 파티션 단위로 데이터를 복제한다.

토픽별 복제 정책을 다르게 가져갈 수 있는데, 토픽을 생성할 때 replication factor를 설정할 수 있다.

복제 개수는 1(복제 X)~브로커 수이다.

출처: https://hoing.io/archives/57262

복제된 파티션은 leader와 follower로 구성된다.

프로듀서와 컨슈머와 직접 통신하는 파티션을 리더라고하고, 리더의 복제본을 가지는 파티션을 팔로워라고 한다.

 

만약 리더 파티션이 존재하는 브로커에 장애가 발생되어 다운된다면, 팔로워 파티션 중 하나가 리더 파티션이 된다.

따라서 데이터가 유실되지 않으며 중단없이 서비스를 지속적으로 운영할 수 있다.

 

데이터가 유실되어도 무관하며 데이터 처리 속도가 중요하다면 복제 갯수는 1 또는 2로 설정한다.

금융 정보와 같이 유실이 일어나면 안되는 경우 복제 갯수는 3이상으로 설정한다.

 

브로커의 역할

1. 컨트롤러

  클러스터의 다수 브로커 중 하나가 컨트롤러 역할을 맡아, 다른 브로커의 상태를 체크하여 파티션을 재분배하는 역할을 한다.

2. 데이터 삭제

  카프카의 데이터는 소비된다고 삭제되지않는다.

  하지만 카프카 브로커의 log.segment.bytes 옵션에 따라 파일 사이즈가 임계값을 넘는 경우 파일을 닫고 삭제한다.

3. 코디네이터

  클러스터의 다수 브로커 중 하나가 코디네이터 역할을 맡아, 컨슈머 그룹의 상태를 체크하고 컨슈머와 파티션의 매칭을 재할당하는 역할을 한다. 이를 리밸런스라고 한다.

 

주키퍼는 무엇일까?

그렇다면 브로커가 동작하는데 주키퍼는 왜 필요할까?

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

 

로컬 환경에서 주키퍼 접속

zookeeper-shell.sh 명령어로 주키퍼에 접속할 수 있다.

접속 후 가장 기본적인 ls / 명령어를 입력하여 루트 하위의 노드들을 확인할 수 있다.

 

조회할 수 있는 정보들

그 외에 주키퍼에 등록된 브로커, 토픽 등의 정보를 조회할 수도 있다.

 

토픽과 파티션

토픽은 카프카에서 데이터를 구분하기 위한 개념이다.

하나의 토픽은 하나 이상의 파티션을 가지고 있고, 이 파티션에 데이터가 저장되게된다.

이렇게 저장되는 데이터를 레코드라고 한다.

 

파티션 기반의 병렬처리 구조

파티션 기반의 구조는 처리량이 한정된 경우 컨슈머를 스케일 아웃하여 병렬 처리할 수 있다는 점에서 이점을 가진다.

 

토픽의 이름을 짓는 것은 변수명을 짓는 것과 마찬가지로 매우 중요하다. (유지보수 관점)

일반적인 컨벤션은 케밥 케이스나 스네이크 케이스를 사용한다.

물론 가장 중요한 것은 규칙을 사전에 정의하고 잘 따르는 것이다.

 

레코드는 타임스탬프, 메시지 키, 메시지 값, 오프셋, 헤더로 구성된다.

타임스탬프는 프로듀서에서 레코드가 생성된 시점의 시간이다. 그러나 임의의 타임스탬프 값을 설정할 수도 있다.

메시지 키는 메시지 값을 순서대로 처리하거나 메시지 값의 종류를 나타내기 위해 사용된다. 

(동일 메시지 키는 동일 파티션에 저장)

오프셋은 브로커에 저장될 때 이전 레코드의 오프셋+1로 생성된다. 이 값을 기준으로 커밋 위치를 파악할 수 있다.

헤더는 레코드의 추가적인 정보를 담는다. (일반적인 HTTP Header와 비슷한 용도)

 

적정 파티션 개수 선정

카프카는 파티션 기반으로 병렬처리 구조를 구성할 수 있기 때문에, 파티션 개수를 설정하는 것은 성능과 밀접한 관련이 있다.

 

파티션 개수를 늘리고 파티션 개수만큼 컨슈머를 추가하는 방법은 데이터 처리량을 늘리는 확실한 방법이다.

적정한 파티션 개수를 선정하기 위해서는 처리해야하는 데이터 양에 따라 계산을 하면 된다.

 

파티션 개수를 결정하기 위한 계산 방법

예를 들어, 프로듀서가 초당 1,000 레코드를 보내고 컨슈머가 초당 100 레코드를 처리한다면 최소한으로 필요한 파티션 개수는 10개이다.

전체 데이터 생성량보다 데이터 소비량이 적다면 컨슈머 렉이 생기고 처리 지연이 발생한다. (데이터 소비속도가 더 빨라야한다)

 

순서를 보장해야하는 경우에 메시지 키를 사용한다면 파티션 개수가 달라지는 경우 순서 보장이 깨질 수 있다.

따라서 이와 같은 경우에는 파티션의 변화가 일어나지 않도록 처음부터 파티션의 개수를 넉넉하게 설정하는 것이 좋다.

 

브로커와 컨슈머에 대한 영향도도 고려해야한다.

파티션이 많아지면 하나의 브로커에서 하나의 프로세스가 여러 파일에 접근해야하는 상황이 발생할 수 있다.

OS 레벨에서 제한이 걸리는 경우가 발생할 수도 있어, 파티션이 너무 많아지는 경우에는 브로커를 늘리는 것을 고려하자.

 

데이터 삭제 정책

카프카 클러스터가 처리하는 모든 데이터는 파일 시스템에 저장된다.

데이터를 삭제하지 않도록 설정한다면 저장소 사용 용량이 늘어남에 따라 운영 비용이 증가할 수 있다.

따라서 cleanup.policy 옵션을 설정하여 삭제 정책을 정의할 수 있다.

 

토픽 삭제 정책 (delete policy)

토픽의 데이터를 세그먼트 단위로 삭제한다.

세그먼트는 파티션마다 별개로 생성되는 단위이며, 세그먼트 파일의 이름은 포함된 오프셋 중 최소값이다.

세그먼트 구조

segment.bytes 옵션으로 1개 세그먼트의 크기를 설정할 수 있다.

retention.ms는 토픽의 데이터를 유지하는 기간을 설정하여 세그먼트 파일의 마지막 수정 시간이 넘어가면 세그먼트는 삭제된다.

retention.bytes에 설정된 파일 크기를 넘어가는 세그먼트 파일을 삭제한다.

 

토픽 압축 정책 (compact policy)

토픽 압축이란 메시지 키별로 오래된 데이터를 삭제하는 정책이다.

따라서 1개 파티션에서의 오프셋 증가가 일정하지 않다. 따라서 가장 오래된 레코드가 아닌 중간의 레코드가 삭제될 수도 있다.

토픽 압축 정책

위의 그림과 같이 메세지 키 별 가장 최근의 데이터를 제외한 데이터를 삭제할 수 있다.

 

min.cleanable.dirty.ratio 옵션값은 액티브 세그먼트를 제외한 세그먼트에 남아있는 데이터의 tail record와 head record의 비율이다.

tail record는 압축이 완료된 레코드, head record는 압축이 되기 전의 레코드이다.

 

압축 정책 예시

위 그림을 예를 들어서 이미 압축된 tail 영역의 개수는 3이고, 압축되지 않은 head 영역의 개수도 3이다.

그렇다면 dirty / (clean + dirty) 라는 공식에 따라서 비율이 0.5로 산정된다.

min.cleanable.dirty.ratio 옵션을 0.5를 설정했다면 위 상태에서 토픽 압축이 실행된다.

 

ISR(In-Sync-Replicas)

하나의 파티션은 여러 브로커에 복제된다.

이 때 기준이 되는 파티션을 리더 파티션이라고하고, 복제될 파티션을 팔로워 파티션이라고 한다.

리더 파티션의 현재 정보를 팔로워 파티션에 복제하는데 시간이 소요되기 때문에 둘 사이의 싱크가 안맞는 경우가 발생할 수 있다.

둘 사이의 싱크가 맞는 경우를 ISR이라고 한다.

 

replica.lag.time.max.ms 설정 값 동작

둘 사이의 싱크가 안맞는 경우를 모니터링하기 위해 replica.lag.time.max.ms 설정으로 시간를 설정한다.

리더 파티션은 팔로워 파티션을 모니터링하며 설정된 값보다 긴 시간동안 복제가 이루어지지 않았으면 팔로워 파티션에 문제가 생긴 것으로 판단한다. (ISR 그룹에서 제외한다)

 

failover 케이스에서 unclean.leader.election.enable 동작

리더 파티션에 문제가 생긴 경우 팔로워 파티션이 리더 파티션의 역할을 위임받는다. 이 때 ISR 그룹에 포함된 파티션이 리더 파티션이 될 자격을 가진다. (리더 파티션과 동기화된 상태이기 때문)

그러나 팔로우 파티션이 없는 경우에는 리더 파티션이 존재하는 브로커가 재시작되기까지 대기한다. (서비스 중단)

이처럼 서비스 중단을 원하지 않는 경우에는 unclean.leader.election.enable를 false로 설정하여 ISR 그룹이 아닌 팔로워 파티션을 리더 파티션으로 선출할 수 있도록 할 수 있다.

그러나 이 경우에는 동기화되지 않은 파티션이 리더 파티션이 되므로 일부 데이터가 유실될 수 있다.

'공부 > Apache Kafka' 카테고리의 다른 글

Producer와 Consumer  (0) 2024.05.05
Kafka 간단하게 시작해보기  (0) 2024.04.14
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함