Apache Kafka 기초

profile image purple-mocha 2024. 2. 19. 23:16

카프카란?

카프카는 링크드인에서 개발한 메시지큐입니다.

 

링크드인에서 앱, 웹, 센서 등에서 취합한 데이터 스틀미을 한곳에서 관리할 목적으로 만들었다고 합니다.

간단하게는 스트리밍 데이터를 다루기 위한 미들웨어와 그 주변 생태계를 말합니다.

 

높은 확장성과 가용성을 가지고 있으며, 데이터 영속성을 지원한다는 것이 큰 특징입니다.

 

카프카의 장점

- 높은 처리량 : 카프카를 통해 많은 양의 데이터를 묶음단위로 처리하여 네트워크 통신횟수를 줄일 수도 있고, 파티션을 나눠 병렬처리도 가능

- 확장성 : 브로커를 최소개수로 운영하다, 스케일 아웃도 가능하며 다시 스케일인 역시 가능

- 영속성 : 다른 메시징 플랫폼과 달리 데이터를 메모리가 아닌 파일시스템에 저장한다. 이는 느린 I/O를 야기할 수 있는데 이때 페이지 캐시 영역을 메모리에 생성해서 사용하므로 높은 처리량을 유지할 수 있다. 이를 통해 메시지를 보존하고 언제든지 읽을 수 있음

- 고가용성 : 보통 브로커를 3대 이상으로 구성. min.insync.replicas 옵션을 사용하면 최소 2개이상의 브로커에 데이터가 복제됨을 보장하는데, 이 설정에서 1대가 장애가 발생하더라도 지속적으로 데이터 처리를 할 수 있음

 

메시징 플랫폼 비교

At Most Once: 최대 한번만 전달, 메시지는 중복되지 않지만 상실될 수 있음

At Least once: 최소 한번만 전달, 메시지가 중복될 가능성은 있지만, 상실되지는 않음

Exactly Once: 메시지 유실없이 단 한 번 전송, 중복되거나 상실되지도 않고 확실하게 메시지가 도달하지만, 성능이 나오지 않음

  Kafka Redis RabbitMQ SQS SNS
메시지 저장 o x x x o
성능 (TPS) 100,000    20,000 300 무제한
메시지 전달 보장 At Most Once
At Least once
Exactly Once
  At Most Once
At Least once
At Least once
Exactly Once
 
선입선출 동일 파티션만 보장 하나의 큐에 하나의 컨슈머만 연결하면 보장 하나의 큐에 하나의 컨슈머만 연결하면 보장 Fifo queue 사용시 보장 x

 

 

구성요소

파티션

데이터를 구분하는 용도로 디비의 테이블과 유사합니다.

파티션에 들어가는 데이터는 레코드라고 부릅니다.

 

처리량을 증가시키고 싶다면 파티션과 컨슈머의 개수를 늘려 스케일아웃을 합니다.

 

파티션 자체는  FIFO 구조의 큐와 유사한데, 다만 메시지가 삭제되지는 않습니다.

 

레코드

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

 

타임스탬프는 프로듀서에서 레코드를 생성한 시점이 디펄트이지만,

임의로 설정할 수 있고, 토픽 설정에 따라 브로커에 적재된 시간으로도 설정할 수 있습니다.

 

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

동일한 메시지키를 가진 레코드는 동일한 파티션에만 들어갑니다.

어느 파티션에 지정될 수 없고 파티션 개수가 바뀔때마다 키와 파티션 매칭이 바뀌는 특징이 있습니다.

 

 

특징

파일저장

카프카는 일반적으로 메모리에 데이터를 적재하는 메시지플랫폼과 달리 파일로 데이터를 저장합니다.

파일 I/O는 속도가 느리지만 카프카는 페이지 캐시를 사용하여 성능을 최대로 끌어올립니다.

때문에 카프카를 실행하는 브로커에서 힙 메모리 사이즈를 크게 설정할 필요가 없습니다.

 

복제

데이터복제는 여러개의 브로커 간 파티션 단위로 이뤄집니다.

토픽을 생성할 때 파티션의 복제 개수를 같이 설정하고, 하나의 리더와 나머지 팔로워로 구성합니다.

리더는 프로듀서 & 컨슈머와 직접 통신을 합니다.

팔로워는 리더의 오프셋을 확인하고 자신과 다르면 데이터를 가져와서 자신에게 복제합니다.

 

브로커 중 한대는 컨트롤러 역할을 하는데, 컨트롤러는 다른 브로커의 상태를 체크하고 리더 파티션을 재분배하는 역할을 합니다.

컨트롤러가 장애가 나면 다른 브로커가 컨트롤러 역할을 상속받는다.

 

브로커중 한 대는 코디네이터 역할을 합니다.

컨슈머 그룹의 상태를 체크하고 파티션을 컨슈머와 매칭되도록 분배하는 역할을 합니다.

컨슈머 하나가 그룹에서 빠지면 매칭되지 않은 파티션을 찾아서 정상 동작하는 컨슈머로 할당해줍니다.

이 과정을 리밸런스라고합니다.

 

데이터 삭제

데이터삭제는 로그세그먼트라고 불리는 파일 단위로 이뤄집니다. 

세그먼트는 바이트는 ms 옵션을 설정해두면 그 값에 따라 파일을 닫는데, 너무 작게 설정해서 자주 여닫으면 부하가 발생하므로 주의해야합니다.

또는 삭제하지 않고 데이터를 압축하는 정책을 사용할 수도 있습니다.

 

컨슈머 / 프로듀서

프로듀서

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

데이터가 전송되고자 할때, 먼저 파티셔너에서 토픽의 어느 파이션으로 전송될 것인지를 정하는데

설정하지 않으면 기본 파티셔너로 정해집니다.

파티셔너에 의해 구분된 레코드는 어커뮬레이터에 데이터를 버퍼로 쌓아두고, 배치로 묶어서 전송합니다.

 

압축 옵션을 설정하면 네트워크 처리량을 줄일 수 있지만, 압축을 하는 CPU 또는 메모리 리소스가 사용되므로 별다른 설정을 하지않으면 압축되지 않은 상태로 전송합니다.

 

파티셔너는 uniformStickyPartitioner와 roundRobinPartitioner가 있습니다.

카프카 2.4부터는 uniformStickyPartitioner가 기본 파티셔너인데요.

라운드로빈은 들어오는대로 순회하며 파티션에 전송하므로 배치로 묶이는 빈도가 적습니다. 하지만 많은 데이터가 배치로 묶여 전송되어야 성능향상을 기대할 수 있습니다.

반면 유니폼스티키는 어커뮬레이터에서 데이터가 배치로 모두 묶일 때까지 기다렸다가 배치 데이터를 한번에 하나의 파티션에 전송하여 향상된 성능을 보여줍니다.

 

컨슈머

컨슈머를 컨슈머 그룹으로 운영하는 경우, 컨슈머 개수는 토픽의 파티션보다 같거나 작아야합니다.

불필요한 스레드가 발생하는 것을 방지하기 위해서입니다.

컨슈머 그룹 내 컨슈머에 장애가 발생하면 해당 컨슈머에 할당된 파티션은 다른 정상 컨슈머에 소유권이 넘어갑니다.

이것을 리밸런싱이라고 부르는데, 컨슈머가 추가되는 상황이나 제외되는 상황에 주로 발생합니다.

리밸런싱은 언제든지 발생가능하므로 데이터 처리 중 발생한 리밸런싱에 대응하는 코드를 작성해야만 하며, 또한 자주일어나면 리밸런싱 중 컨슈머 그룹의 컨슈머들은 데이터를 읽을 수 없기때문에 자주 일어나는 것은 서비스에 영향을 줄 수 있습니다.

 

컨슈머는 커밋을 통해 데이터를 정상적을 처리했는지 기록하는데 이는 __consumer_offsets 토픽에 기록됩니다.

해서, 데이터 처리 중복이 발생하지 않게 하기 위해 컨슈머 애플리케이션 오피셋 커밋을 정상적으로 처리했는지도 검증해야합니다.

비명시 오프셋 커밋은 일정 시간이 지나면 자동으로 오프셋을 커밋하는데 이는 편리한 반면 리밸런싱이나 컨슈머 강제종료시 데이터 중복 또는 유실이 될 수 있어서 취약하다고 볼 수 있습니다. 

 

리밸런싱

위에서 얘기했듯, 리밸런싱은 파티션과 컨슈머의 매칭이 바꾸는 작업입니다.

리밸런싱이 일어나는 동안은 컨슈밍이 중지되기 때문에 자주 발생하지 않도록 하는 것이 좋습니다.

또한, 컨슈머가 데이터를 처리하는 중에 리밸런스가 발생되게되면 중복 처리 가능성이 생길 수 있으니 이를 고려한 애플리케이션 설계가 필요합니다.

 

리밸런싱이 일어나는 상황

  1. 컨슈머 생성/삭제
    • 컨슈머가 종료되고 새로 시작되면서 두번의 리밸런싱 발생
  2. heartbeat timeout
    • heartbeat는 Consumer가 살아있다고 Coordinator 에게 알려줌
    • 신호를 받지 못하면 리밸런싱 발생
  3. poll timeout
    • 컨슈머가 메시지를 처리 후 poll 요청을 보내는데
    • 메시지 처리 시간이 길어져 원래 poll interval 시간을 넘기게 되면 리밸런싱이 발생
  4. 컨슈머 장애
    • 컨슈머와 세션이 종료되면 컨슈머는 컨슈머그룹에서 제외되고 리밸런싱이 진행

리밸런싱 과정

  1. 리밸런싱 상황 발생
  2. 그룹 내 컨슈머는 poll요청을 하면서 코디네이터에 조인 요청
  3. 코디네이터는 rebalanceTimeout내에 그룹의 모든 컨슈머에 조인요청을 받으면 그 중 하나를 리더러 선정
  4. 리더 컨슈머는 팔로워 컨슈머의 파티션 할당을 결정하고 코디네이터에게 알림
  5. 팔로워 컨슈머는 조인요청 응답을 받고 다시 코디네이터에게 파티션 목록을 요청

리밸런싱 해결방안

  1. 리밸런싱 시간 단축
    • 실제 poll 호출 간격은 레코드하나당 처리시간 * 한번의 poll로 가져온 레코드 수 이므로,
    • max.poll.records(한번의 poll로 가져온 레코드 수) 값을 작게하여 poll 요청을 자주하도록 변경
  2. poll 요청 자주 보내기
    • max.poll.records 값을 작게하여 poll 요청을 자주하도록 변경
  3. 커밋전략 변경
    • ack 전략이 가장 많은 poll요청을 보내므로, batch나 manual로 변경