[아파치 카프카 애플리케이션 프로그래밍] 카프카 개념

jj J·2023년 6월 29일
0

Kafka

목록 보기
1/3

팀 내 IoT 서비스에서 발생하는 이벤트를 로깅해 추천 모델 학습 데이터로 활용, ElasticSearch를 통한 분석 데이터로 활용, 반응형 앱 데이터로 활용 등 하나의 이벤트 데이터 스트림에서 다양한 서드 파티 서비스를 붙여야 하는 니즈가 발생했다.
이 니즈를 카프카로 데이터 스트림을 만들고, 카프카 커넥트로 필요한 서비스들을 컨슈머로 붙여 해결하면 좋을 것 같아 카프카 공부를 시작해보려한다.

평소 책이나 강의를 눈으로 보는 것보다 타자로 타이핑하며 요점을 필기하며 보는 편인데, 이 내용을 추후 다시 돌아보기도 하고, 기록보다는 공유가 좋을 것 같아 글을 작성한다.

카프카 개념

주키퍼

  • 카프카 클러스터 운영하기 위해 반드시 필요
  • 카프카 2까지는 반드시 필요했고, 3부터는 반드시 필요하진않음
  • 아직까진 완벽히 대체 어렵기 때문에 아직은 주키퍼 필수

브로커

  • 하나의 서버나 인스턴스 위에서 동작함
  • 1개로도 기본 기능 실행 가능
  • 하지만, 3개 이상의 브로커 서버를 1개의 클러스터로 묶어 운영
  • 데이터를 안전하게 분산 저장하고, 복제해 장애로부터 가용성 확보 가능

컨트롤러

  • 클러스터의 다수 브로커 중 한 대가 컨트롤러 역할
  • 다른 브로커들의 상태를 체크하고 브로커가 클러스터에서 빠지는 경우 해당 브로커에 존재하는 리더 파티션을 재분배
  • 카프카는 지속적으로 데이터를 처리해야하므로, 브로커의 상태가 비정상이라면 빠르게 클러스터에서 빼내는 것이 중요
  • 컨트롤러 역할을 하는 브로커에 장애가 생기면 다른 브로커가 컨트롤러 역할을 함

데이터 삭제

  • 컨슈머가 데이터를 가져가도 토픽의 데이터는 삭제되지 않음
  • 컨슈머나 프로듀서가 데이터 삭제를 요청할 수도 없음
  • 브로커만 데이터를 삭제 가능
  • 데이터 삭제는 파일 단위로 이뤄지는데, 이 단위를 ‘로그 세그먼트’라고 부른다
  • 세그먼트에는 다수의 데이터가 들어있고, 일반 DB 처럼 특정 데이터를 선별해서 삭제할 수 없음

컨슈머 오프셋 저장

  • 컨슈머 그룹은 토픽이 특정 파티션으로부터 데이터를 가져가 처리하고 이 파티션의 어느 레코드까지 가져갔는지 확인하기 위해 오프셋을 커밋함
  • 커밋한 오프셋은 __consumer_offsets 토픽에 저장
  • 여기에 저장된 오프셋을 토대로 컨슈머 그룹은 다음 레코드를 가져가 처리함

그룹 코디네이터

  • 컨슈머 그룹의 상태를 체크하고, 파티션을 컨슈머와 매칭되도록 분배
  • 컨슈머가 컨슈머 그룹에서 빠지면 매칭되지 않은 파티션을 정상 동작하는 컨슈머로 할당하여 끊임없이 데이터가 처리되도록 함
  • 이렇게 파티션을 컨슈머로 재할당하는 과정을 리밸런스라고 함

세그먼트와 삭제

  • 삭제 기준은 기간, 적재 용량
  • 주의점 : 쌓이는 데이터의 양 X 보유 기간이 현재 파일시스템 최대 용량보다 크면 문제가 됨. 이를 미리 산정해서 보유 기간을 설정하는 것이 중요
  • 일반적으로는 3일로 지정(토일 대응 안되니까)
  • 데이터는 세그먼트 단위로 삭제가 발생하기 때문에 레코드 단위 삭제는 불가능, 한번 적재된 레코드는 수정이 불가하기 때문에 데이터 적재 시(프로듀서) 또는 데이터 사용(컨슈머) 시 데이터를 검증하는 것이 좋다

압축

  • 메시지 키 별로 해당 메시지 키의 레코드 중 오래된 데이터를 삭제하는 정책
  • 삭제(delete) 정책과 다르게 일부 레코드만 삭제될 수 있다.
  • 마찬가지로 액티브 세그먼트 데이터는 영향을 주지 않는다
  • 테일(클린), 헤드(더티)로 나뉨
    • 테일 영역 : 압축 정책에 의해 압축이 완료된 레코드들, 중복 메시지 키가 없음
    • 헤드 영역 : 압축 정책이 되기 전 레코드들. 중복 메시지 키가 있다

압축 시점

  • 압축 시작 시점은 min.cleanable.dirty.ratio 값을 따름
  • 액티브 세그먼트를 제외한 세그먼트에 남아있는 테일 영역의 레코드 개수와 헤드 영역의 레코드 개수의 비율을 뜻함
  • 0.5로 설정하면, 테일 영역과 헤드 영역의 레코드 개수가 동일할 경우 압축 실행됨
  • 0.9와 같이 크게 설정하면 한번 압축할 때 많은 데이터가 줄어서 효과가 좋지만, 0.9 비율이 될 때까지 용량을 차지하므로 용량 효율이 좋지 않음
  • 반면, 0.1과 같이 작게 설정하면 압축이 자주 일어나서 가장 최신 데이터만 유지할 수 있지만 압축이 자주 발생하기 때문에 브로커에 부담을 줄 수 있음

복제

  • 브로커 중 일부에 장애가 발생하더라도 데이터를 유실하지않고 안전하게 사용하기 위한 방법
  • 복제는 파티션 단위로 이루어짐
  • 토픽 생성 시 파티션 복제 개수로 같이 설정되는데, 선택하지 않으면 브로커에 설정된 옵션값 따라감
  • 최소값은 1(복제 없음), 최댓값은 브로커 개수만큼

복제 - 리더와 팔로워

  • 복제된 파티션은 리더와 팔로워로 구성됨
  • 프로듀서 또는 컨슈머와 직접 통신하는 파티션을 리더, 나머지 복제 데이터를 가지고 있는 파티션을 팔로워라고 부름
  • 팔로워들은 리더의 오프셋을 확인해 현재 자신의 오프셋과 차이날 경우, 리더로 부터 데이터를 가져와 자신의 파티션에 저장하는데 이 과정을 ‘복제’라고 한다

복제 - 장단점

  • 장점 : 복제를 통해 데이터를 안전하게 사용할 수 있음. 가용성 확보
    • 카프카 운영 시 2 이상의 복제 개수를 정하는 것이 중요
  • 단점 : 복제 개수만큼의 저장 용량이 증가함

복제 - 장애 발생 시

  • 브로커가 다운되면 팔로워 파티션 중 하나가 리더 파티션 지위를 넘겨받는다
  • 이를 통해, 데이터가 유실되지 않고 컨슈머나 프로듀서와 데이터를 주고받도록 동작할 수 있다
  • 운영 시 에는 데이터 종류마다, 토픽마다 다른 복제 개수를 설정해 운영하기도 함
  • 데이터가 일부 유실되어도 무관하고 데이터 처리 속도가 중요하면 1 또는 2로 복제 개수 설정
  • 금융 정보와 같이 유실이 일어나면 안되는 데이터의 경우 복제 개수를 3으로 설정하기도 함

ISR(In Sync replicas)

  • 리더와 팔로워가 모두 싱크가 된 상태를 뜻함
  • 리더의 모든 데이터가 팔로워에 모두 동기화 되었다는 뜻
  • ISR에 포함되지 못한 팔로워 파티션이 리더 파티션이 되면 데이터가 유실될 수 있음
  • 유실이 발생하더라도 서비스 중단없이 지속적으로 토픽을 사용하고 싶으면 unclean.leader.election.enable=true 를 사용할 수 있다.
  • false라면 해당 브로커가 복구될 때 까지 중단시킨다
  • 토픽 단위로 옵션을 지정할 수 있다

토픽과 파티션

  • 토픽 : 카프카에서 데이터를 구분하기 위해 사용하는 단위
  • 토픽은 1개 이상의 파티션을 소유함
  • 파티션에는 프로듀서가 보낸 데이터들이 들어가 저장되는데, 이 데이터를 ‘레코드’라고 부른다
  • 파티션은 큐와 유사한 구조로 먼저 들어간 레코드는 컨슈머가 먼저 가져간다
  • 다만, 큐는 데이터를 가져가면 삭제하지만 카프카는 삭제하지 않는다
  • 이러한 특징 때문에 토픽의 레코드는 다양한 목적을 가진 여러 컨슈머 그룹들이 여러번 가져갈 수 있다

토픽 생성 시 파티션이 배치되는 방법

  • 파티션이 5개인 토픽 생성 시 0번 브로커부터 시작하여 라운드 로빈 방식으로 리더 파티션들이 생성된다
  • 카프카 클라이언트는 리더 파티션이 있는 브로커와 통신하여 데이터를 주고 받으므로 여러 브로커에 골고루 네트워크 통신을 하게 됨
  • 이를 통해, 데이터가 특정 서버(브로커)와 통신이 집중되는(hot spot) 현상을 막고, 선형 확장(linear scale out)을 하여 데이터가 많아지더라도 자연스럽게 대응할 수 있게 됨
  • 팔로워 파티션은 리더 파티션이 없는 나머지 브로커에 배치됨

특정 브로커에 파티션이 쏠리는 현상

  • 카프카 클러스터 운영 시 주의해야할 점임
  • 리더 파티션이 하나의 브로커에 몰리면 부하가 커짐
  • 이런 경우 kafka-reassign-partitions.sh 명령으로 파티션을 재분배할 수 있다

파티션 개수와 컨슈머 개수의 처리량

  • 파티션은 카프카 병렬처리의 핵심으로 그룹으로 묶인 컨슈머들이 레코드를 병렬로 처리할 수 있도록 매칭됨
  • 컨슈머의 처리량이 한정된 상황에서 많은 레코드를 병렬로 처리하는 가장 좋은 방법은 컨슈머의 개수를 늘려 스케일 아웃하는 것
  • 컨슈머 개수를 늘림과 동시에 파티션 개수도 늘리면 처리량이 증가하는 효과를 볼 수 있다

파티션 개수를 줄이는 것은 불가능

  • 파티션 개수를 줄이는 것은 불가능하기 때문에 파티션을 늘릴 때는 신중히 해야함
  • 토픽을 삭제하고 재생성하는 것 이외에 줄이는 것 불가능

레코드

  • 타임스탬프, 헤더, 메시지 키, 오프셋으로 구성됨
  • 프로듀서가 생성한 레코드가 브로커로 전송되면 오프셋과 타임스탬프가 지정되어 저장됨

레코드-타임스탬프

  • 스트림 프로세싱에서 활용하기 위한 시간을 저장하는 용도로 사용됨

레코드-오프셋

  • 프로듀서가 생성한 레코드에는 존재하지 않음
  • 프로듀서가 전송한 레코드가 브로커에 적재될 때 오프셋이 지정됨
  • 오프셋은 0부터 시작되고 1씩 증가함
  • 컨슈머는 오프셋을 기반으로 처리가 완료된 데이터와 앞으로 처리해야할 데이터를 구분함
  • 각 메시지는 파티션별로 고유한 오프셋을 가지므로 컨슈머에서 중복 처리를 방지하기 위한 목적으로도 사용함

레코드-헤더

  • key/value 데이터를 추가할 수 있으며, 레코드의 스키마 버전이나 포맷과 같이 데이터 프로세싱에 참고할만한 정보를 담아서 사용할 수 있음

레코드-메시지 키

  • 처리하고자 하는 메시지 값을 분류하기 위한 용도로 사용되며, 이를 파티셔닝이라 함
  • 파티셔닝에 사용하는 메시지 키는 파티셔너에 따라 토픽의 파티션 번호가 정해짐
  • 메시지 키는 필수값이 아니며, 지정하지 않으면 null로 설정됨
  • 메시지 키가 Null인 레코드는 특정 토픽의 파티션에 라운드 로빈으로 전달됨
  • null이 아닌 메시지 키는 해쉬값에 의해서 특정 파티션에 매핑되어 전달됨(순서 보장 가능)

레코드-메시지 값

  • 메시지 값은 실질적으로 처리할 데이터가 담기는 공간
  • 메시지 값의 포맷은 제네릭으로 사용자에 의해 지정됨
  • Float, Byte, String 등 다양한 형태 지정 가능하며 필요에 따라 사용자 지정 포맷으로 직렬화/역직렬화 클래스를 만들어 사용할수도 있다.
  • 브로커에 저장된 레코드의 메시지 값은 어떤 포맷으로 직렬화되어 저장되었는지 알 수 없기 때문에 컨슈머는 미리 역직렬화 포맷을 알고 있어야 함
  • 일반적으로 String으로 포맷 처리하는데, float나 int 대비 공간 낭비 발생할 수 있음

유지보수하기 좋은 토픽 이름

  • 카프카 내부 로직 때문에 토픽 이름에 마침표와 언더바가 동시에 들어가면 안됨
  • 따라서, 하이픈과 영어, 숫자로 구성하는 것이 좋다
  • 토픽 이름이 모호하면 유지보수 시 큰 어려움을 겪을 수 있음
  • 토픽 이름에 대한 규칙을 사전에 정의하고, 그 규칙을 다같이 따르는 것이 중요
  • 토픽 이름 변경도 불가하므로, 토픽 이름 규칙 준수가 중요
  • 예시
    • <환경>.<팀명>.<애플리케이션명>.<메시지타입>
      • prd.marketing-team.sms-platform.json

클라이언트 메타데이터

  • 카프카 클라이언트는 통신하고자 하는 리더 파티션의 위치를 알기 위해 데이터를 주고(프로듀서) 받기(컨슈머) 전에 메타데이터를 브로커로부터 전달받음

클라이언트 메타데이터가 이슈 발생한 경우

  • 카프카 클라이언트는 반드시 리더 파티션과 통신해야함
  • 만약, 메타데이터가 현재의 파티션 상태에 맞게 리프레시되지 않은 상태에서 잘못된 브로커로 데이터를 요청하면 LEADER_NOT_AVAILABLE 익셉션이 발생함
  • 이 에러는 클라이언트(프로듀서 또는 컨슈머)가 데이터를 요청한 브로커에 리더 파티션이 없는 경우 나타나며 대부분의 경우 메타데이터 리프레시 이슈로 발생
  • 이 에러가 자주 발생한다면 메타데이터 리프레시 간격을 확인하고 클라이언트가 정상적인 메타데이터를 가지고 있는지 확인해야함

출처 : 인프런 - [아파치 카프카 애플리케이션 프로그래밍] 개념부터 컨슈머, 프로듀서, 커넥트, 스트림즈까지!

profile
매일 발전

0개의 댓글