[Kafka] 2. 카프카 기본 개념과 구조

카프카 구성요소

카프카의 구성요소입니다.


브로커 (broker)

카프카가 설치된 서버 혹은 노드

프로듀서 (producer)

카프카로 메시지를 보내는 클라이언트

컨슈머 (consumer)

카프카에서 메시지를 가져가는 클라이언트

주키퍼 (zookeeper)

카프카의 메타데이터 및 각 노드 상태 관리를 담당하는 어플리케이션. Apache의 독립 프로젝트로 카프카 뿐만 아니라 클러스터 단위로 운영되는 다른 어플리케이션들에도 사용되고 있다.

토픽

메시지 저장을 구분하는 가장 큰 단위. 하나의 브로커에 토픽은 1개 이상이어야 하고, 프로듀서가 메시지를 보낼 때 어떤 토픽으로 보낼지 토픽을 필수로 지정해야 한다.

파티션

병렬 처리 등 성능향상을 위해 토픽을 여러개로 나눈 단위

세그먼트

프로듀서가 전송한 메시지는 브로커 로컬 디스크에 파일로 저장되는데, 이를 세그먼트라고 한다.

메시지 / 레코드

프로듀서가 브로커로 전송하거나 컨슈머가 꺼내가는 데이터의 단위.


카프카 기초

리플리케이션

카프카는 고가용성 보장을 위해 메세지를 복제해 클러스터 내 브로커에 분산시키고, 이를 통해 브로커 하나가 죽더라도 안정적으로 메시징 시스템을 유지할 수 있습니다. 리플리케이션은 토픽 내의 파티션을 대상으로 합니다.

  • 프로듀서가 토픽에 메세지를 보내면 N개의 파티션에 동일한 메세지가 병렬로 전달된다.
  • 각 파티션에 붙어있는 컨슈머들에게 병렬로 메세지 처리가 된다.
  • 이 때 파티션 하나가 기능을 하지 못하면 파티션에 붙어있는 컨슈머가 메세지를 받지 못하게 되는데, 이를 대비해 복제본을 항시 유지해 복제본이 원본의 역할을 바로 대신할 수 있도록 한다.

리플리케이션의 기능은 이렇게 정리할 수 있으며, 리플리케이션이 몇개냐에 따라서 리더(Leader) / 팔로워(Follower)로 나누어 관리합니다.

리플리케이션 갯수가 많으면 안정성은 높아지겠지만 디스크 리소스를 그만큼 많이 사용하기 때문에 복제 오버헤드를 감당할 수 있는 한도 내에서 리플리케이션을 유지하는 것이 효율적입니다. 보통 운영환경에서는 최소 3개 이상의 리플리케이션을 두어 유실에 대한 안정성을 확보합니다. 그 이상부터는 리소스가 오버헤드를 감당할 수 있는가에 따라 달라지겠습니다.


파티션

프로듀서는 메시지를 토픽에 전송합니다. 컨슈머도 결국 토픽에 붙어 메시지를 당겨가는데, 컨슈머가 많으면 많을수록 하나의 토픽이 한번에 처리하기가 어려워집니다.

이를 개선하기 위해 하나의 토픽을 파티션이라는 단위로 나눠서 관리합니다. 프로듀서가 토픽에 보낸 메시지는 파티션 갯수만큼 병렬처리됩니다.

img

늘어난 파티션 수만큼 consumer를 붙일 수 있습니다. 그렇다면 파티션은 많으면 많을수록 좋을까요?

당연히 아닙니다. 파티션이 늘어나면 당연히 디스크 용량, I/O, 메타데이터를 관리하는 주키퍼 등에 부담이 되기 때문에 적당한 수의 파티션을 유지하는 것이 좋습니다. 특히 파티션 수는 운영중에 늘리는 것은 가능하지만 줄일수는 없기 때문에 초기에는 작게 잡고 처리량에 따라 점점 늘려가는 것이 좋은 방법입니다.


세그먼트

프로듀서가 송신한 메시지는 파일로 저장된다고 했습니다. 그런데 파티션이 나눠진다면 어떤 형태로 저장될까요?

image

파일은 세그먼트라는 로그 파일(.log)의 형태로 브로커의 로컬 디스크에 저장됩니다. 각 파티션에는 N개의 세그먼트 로그 파일이 존재합니다.

image

정리해보면,

  • 프로듀서는 브로커의 토픽으로 메시지를 전송한다.
  • 토픽은 1개 이상의 파티션으로 구성되어 있고, 프로듀서로부터 받은 메시지를 파티션의 세그먼트 로그 파일로 기록한다.
  • 브로커의 세그먼트 로그 파일에 저장된 메시지를 컨슈머가 읽어간다.

입니다.


카프카 핵심 개념

분산 시스템

분산 시스템은 다음과 같은 장점을 가집니다.

  • 고가의 서버를 사는 것보다 더 저렴한 가격으로 성능을 보장할 수 있습니다.
  • 하나의 서버가 장애를 일으켰을 때 다른 서버로 장애대응이 가능합니다.
  • 장비를 추가해 확장에 용이합니다.

페이지 캐시

카프카는 높은 처리량을 보장하기 위해 OS의 페이지 캐시를 사용합니다. 디스크가 아닌 메모리에 데이터를 일부 저장해 디스크 I/O 횟수를 줄이고 성능을 높일 수 있습니다.

image

배치 처리

카프카는 배치성 처리도 가능합니다. 당연히 단건 전송보다 액세스 횟수가 줄어들고 네트워크 비용도 줄어드니 카프카 효율이 좋아집니다. 컨슈머가 실시간성으로 빠르게 데이터를 가져가야 하는 경우에는 어쩔 수 없겠지만, 배치성으로 주기를 길게 가져가도 상관없는 작업이라면 배치성으로 broker에서 데이터를 가져가는 것이 좋겠습니다.

압축 전송

카프카에서는 메시지 전송 시 압축 전송을 권장합니다. 앞서 언급한 배치 처리와 더불어 네트워크 비용을 줄일 수 있는 방법입니다. snappy, gzip 등 대중적인 압축방식을 지원하고 있기 때문에 raw data를 그대로 보내는것보다는 메시지를 압축하는 것이 좋겠습니다.

일반적으로 높은 압축률을 원하면 snappy, 빠른 응답속도를 원한다면 gzip을 권장하지만 환경에 따라 최적의 압축방식은 다르기 때문에 테스트 후 사용하는 것이 좋겠습니다.

주키퍼

주키퍼는 카프카 뿐만 아니라 hadoop, hbase 등 많은 분산 어플리케이션의 코디네이터 역할을 합니다. 주키퍼는 여러 노드가 있는 환경에서 안정적으로 서비스가 가능한지 여부를 판단하고 관리하는 역할을 합니다.

살아있는 노드가 과반수 이상 유지되고 있다면 가용한 서비스라고 판단합니다. 그래서 주키퍼는 반드시 홀수로 구성해야 합니다.

주키퍼는 znode라는 시스템을 사용해 카프카 노드들의 메타데이터를 기록하고 관리합니다. 메시지를 저장하는 것이 아니기 때문에 그 크기가 작고 모든 데이터를 디스크가 아닌 메모리 공간에 저장합니다. 메모리 I/O로 장애 대응시 빠른 대처 및 leader 선정 등이 가능합니다.

그러나 주키퍼의 한계가 점점 드러났습니다. 토픽에 파티션이 많다면 broker <-> zookeeper 간의 네트워크 부하는 늘어나게 되고, scale out으로 카프카를 확장하는 것과는 별개로 zookeeper의 늘어나는 네트워크 비용과 메모리 I/O를 해결하기가 점점 어려워졌습니다.

그 결과로 kafka 3.0부터는 zookeeper가 없는 kafka가 출시되었습니다. 블로그 포스팅 참고

물론 아직 완전히 zookeeper를 떼어낼수는 없습니다. 앞으로는 zookeeper가 아닌 KRaft라는 새로운 개념으로 노드 및 카프카 리소스 관리를 한다고 하니 살펴보는 것도 좋을 것 같습니다.

프로듀서