티스토리 뷰

토픽 & 파티션

  • 토픽은 카프카에서 데이터를 구분하기 위해 사용하는 단위이다.
  • 파티션에는 프로듀서가 보낸 데이터들이 들어가 저장되는데 이 데이터를 레코드라고 부르며, 1개 이상의 파티션을 소유하고 있다.
  • FIFO 구조와 같이 먼저 들어간 레코드를 컨슈머가 먼저 가져가게 된다.
  • 일반적인 자료구조의 큐는 데이터를 가져가면 삭제 되지만 카프카에서는 삭제되지 않고, 파티션의 레코드는 컨슈머가 가져가는 것과 별개로 관리된다.
  • 이런 특징때문에 토픽의 레코드는 다양한 목적을 가진 여러 컨슈머 그룹들이 토픽의 데이터를 여러번 가져갈 수 있다.

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

  • 파티션이 5개인 토픽을 생성했을 경우, 첫 번째 그림과 같이 0번 브로커부터 시작하여 round-robin 방식으로 리더 파티션들이 생성된다.
  • 카프카 클라이언트는 리더 파티션이 있는 브로커와 통신하여 데이터를 주고 받으므로, 여러 브로커에 골고루 네트워크 통신을 하게 된다.
  • 이를 통해, 데이터가 특정 서버(여기서는 브로커)와 통신이 집중되는(hot spot) 현상을 막고, scale out 하여 데이터가 많아지더라도 자연스럽게 대응할 수 있게 된다.

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

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

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

  • 카프카에서 파티션 개수를 줄이는 것은 지원하지 않기 때문에 파티션를 늘리는 작업을 할 때는 신중히 파티션 개수를 정해야 한다.
  • 한번 늘리면 줄이는 것은 불가능하기 때문에 토픽을 삭제하고 재생성하는 방법 외에는 없기 때문이다.
  • 카프카에서는 파티션의 데이터를 세그먼트로 저장하고 있으며, 만에 하나 지원을 할지라도 여러 브로커에 저장된 데이터를 취합하고 정렬해야하는 복잡한 과정을 거쳐야 하기 때문에 클러스러에 큰 영향이 가게 된다.

레코드

  • 레코드는 타임스탬프, 헤더, 메시지 키, 메시지 값, 오프셋으로 구성되어 있다.
  • 프로듀서가 생성한 레코드가 브로커로 전송될 때, 오프셋과 타임스탬프(옵션에 따라)가 지정되어 저장된다.
  • 브로커에 한번 적재된 레코드는 수정할 수 없고, 로그 리텐션 기간 또는 용량에 따라서만 삭제된다.

레코드-타임스탬프

  • 레코드의 타임스탬프는 스트림 프로세싱에서 활용하기 위한 시간을 저장하는 용도로 사용된다.
  • 카프카 0.10.0.0 이후 버전부터 추가된 타임스탬프는 Unix timestamp 가 포함되며, 프로듀서에서 따로 설정하지 않으면 기본값으로 ProducerRecord 생성 시간이 들어간다.
  • 브로커 적재 시간(LogAppendTime)으로 설정할 수도 있다.

레코드-오프셋

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

레코드-헤더

  • 레코드의 헤더는 0.11부터 제공된 기능이다.
  • key/value 데이터를 추가할 수 있으며, 레코드의 스키마 버전이나 포맷과 같이 데이터 프로세싱에 참고할만한 정보를 담아서 사용할 수 있다.

레코드-메시지 키

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

레코드-메시지 값

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

토픽 이름 제약 조건

  • 빈 문자열 토픽 이름은 지원하지 않는다.
  • 토픽 이름은 마침표 하나(.) 또는 마침표 둘(..)로 생성할 수 없다.
  • 토픽 이름의 길이는 249자 미만으로 생성되어야 한다.
  • 토픽 이름은 영어 대/소문자와 숫자 0~9, 마침표(.) 언더바(_), 하이픈(-) 조합으로 생성할 수 있고, 그 외의 문자열이 포함된 토픽 이름은 생성할 수 없다.
  • 카프카 내부 로직 관리 목적으로 사용되는 2개 토픽(__consumer_offsets, __transaction_state)과 동일한 이름으로 생성 불가능하다.
  • 카프카 내부적으로 사용하는 로직으로 인해 토픽 이름에 마침표(.)와 언더바(_)를 동시에 사용해서는 안 된다. 생성은 가능하지만 사용시 이슈가 발생할 수 있기 때문에 마침표(.)와 언더바(_)가 들어간 토픽 이름을 사용하면 WARNING 메시지가 발생한다.

클라이언트 메타데이터

  • 카프카 클라이언트는 통신하고자 하는 리더 파티션의 위치를 알기 위해 데이터를 주고(프로듀서) 받기(컨슈머) 전에 메타데이터를 브로커로부터 전달받는다.
  • 메타데이터는 다음과 같은 옵션을 통해 리프레쉬(refresh) 된다.
    • metadata.max.age.ms: 메타데이터를 강제로 리프레쉬하는 간격, 기본값은 5분
    • metadata.max.idle.ms: 프로듀서가 유휴상태일 경우 메타데이터를 캐시에 유지하는 기간(예를 들어 프로듀서가 특정 토픽으로 데이터를 보낸 이후 지정한 시간이 지나고 나면 강제로 메타데이터를 리프레쉬), 기본값은 5분

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

  • 카프카 클라이언트는 반드시 리더 파티션과 통신해야 한다.
  • 메타데이터가 현재의 파티션 상태에 맞게 refresh되지 않은 상태에서 잘못된 브로커로 데이터를 요청하면 LEADER_NOT_AVAILABLE Exception이 발생한다.
  • LEADER_NOT_AVAILABLE Exception 은 클라이언트(프로듀서 또는 컨슈머)가 데이터를 요청한 브로커에 리더 파티션이 없는 경우 나타나며, 대부분의 경우 메타데이터 refresh 이슈로 발생한다. 이 에러가 자주 발생한다면, 메타데이터 refresh 간격을 확인하고 클라이언트가 정상적인 메타데이터를 가지고 있는지 확인해야 한다.
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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
글 보관함