카프카(Kafka) 또는 카프카 클러스터(Kafka Cluster)는 분산 스트리밍 플랫폼으로써, 여러 대의 브로커를 구성한 클러스터를 의미한다. 카프카는 링크드인(LinkedIn)의 개발자 세 명(제이 크렙스, 준 라오, 네하 나크헤데)이 만든 것이 시초였으며, 2011년 아파치 오픈소스로 공개된 아파치 프로젝트 애플리케이션이다.
주키퍼(Zookeeper)
: 아파치 프로젝트 애플리케이션으로 카프카의 메타데이터(metadata) 관리 및 브로커의 정상상태 점검(health check) 을 담당 합니다.
카프카(Kafka) 또는 카프카 클러스터(Kafka cluster)
: 아파치 프로젝트 애플리케이션으로 여러대의 브로커를 구성한 클러스터를 의미 합니다.
브로커(broker)
: 카프카 애플리케이션이 설치된 서버 또는 노드를 의미 합니다.
프로듀서(producer)
: 카프카로 메세지를 보내는 역할을 하는 클라이언트로 총칭 합니다.
컨슈머(consumer)
: 카프카에서 메세지를 꺼내가는 역할을 하는 클라이언트를 총칭 합니다.
토픽(topic)
: 카프카는 메시지 피드들을 토픽으로 구분하고, 각 토픽의 이름은 카프카 내에서 고유 합니다.
파티션(partition)
: 병렬 처리 및 고성능을 얻기 위해 하나의 토픽을 여러개로 나눈 것을 의미 합니다
세그먼트(segment)
: 프로듀서가 전송한 실제 메세지가 브로커의 로컬 디스크에 저장되는 파일을 말합니다.
메세지(message) 또는 레코드(record)
: 프로듀서가 브로커로 전송하거나 컨슈머가 읽어가는 데이터 조각을 말합니다.
실제 서비스에서 사용되는 카프카는 고가용성을 위해 '여러 개의 Kafka 서버와 Zookeeper로 구성된 클러스터 구조'로 사용되는데요.
일반적으로 3개 이상의 kafka 서버(Broker)로 구성되며, 이러한 구조를 통해 broker에 저장된 메시지를 다른 broker에게 공유하고 하나의 브로커에 문제가 생겼을 때, 다른 브로커로 그 역할을 대체해서 시스템을 정상적으로 유지시키는 방식으로 동작합니다.
각각의 카프카 서버를 kafka broker라고 하며(또는 bootstrap server), n개의 broker 중 1대는 리더의 역할을 수행합니다.
'Zookeeper'는 분산 어플리케이션의 데이터 관리 기능을 가지고 있으며, 여러 개의 broker 들을 컨트롤해 주는 역할을 수행합니다.
때문에 zookeeper 없이 kafka가 동작할 수 없다는 특징이 있습니다.
(multi broker들 간의 정보 변경 공유 및 동기화 등을 수행)
데이터를 최종적으로 저장하는 곳인데, 데이터를 구분하기 위한 저장소라고 보면 된다.또한 토픽은 데이터베이스 테이블이나, 파일시스템의 폴더와 유사한 성질을 가지고 있다고 말할 수 있다.
💡 topic은 목적에 따라 각각의 이름을 가질 수 있는데 무슨 데이터를 담는지에 따라 명확하게 명명하는 것을 권장한다.
토픽은 카프카에서 Producer 와 Consumer 를 분리하는 중요한 컨셉이다. Producer 는 카프카의 토픽에 메시지를 저장 (Push) 하고 Consumer 는 저장된 메시지를 읽어 (Pull) 온다. 하나의 토픽에 여러 Producer / Consumer 가 존재할 수 있다.
하나의 “토픽(topic)”이 한번에 처리할 수 있는 단계를 높이기 위해서 “토픽(topic)”을 여러 개로 나눠 병렬 처리가 가능하게 만든 것을 “파티션(partition)”이라고 한다.
위와 같이 하나의 토픽을 여러 개로 나누면 분산 처리가 가능해지며, 파티션 수만큼 컨슈머를 연결할 수 있게 됩니다.
파티션 수도 토픽을 생성할 때 옵션으로 설정하게 되며, 사실 파티션 수를 정하는 기준은 다소 모호한 경우가 많습니다. 인터넷에서는 적절한 파티션 수를 구하는 공식도 간혹 있으나 각 메세지 크기나 초당 메세지 건수 등에 따라서 달라짐으로 정확한 예측은 사실 어렵습니다.
특히 파티션수는 초기 생성 후 언제든지 늘릴 수 있지만, 반대로 한번 늘린 파티션 수는 절대로 줄일 수 없습니다.
따라서 초기에 토픽 생성시에는 파티션수를 작게 적절하게(2또는 4정도) 생성 한 후, 메세지 처리량인 컨슈머의 LAG 등을 모니터링 하면서 조금씩 늘려가는 방법이 가장 좋습니다.
여기서 컨슈머의 LAG 이란 '프로듀서가 보낸 메세지수(카프카에 남아 있는 메세지 수) - 컨슈머가 가져간 메세지 수' 를 의미 합니다.
컨슈머의 지연이 없다면(모든 메세지를 가져갔다면)
5-5=0
이 되게 됩니다.
카프카에서는 원본 파티션을 리더(leader)라고 부르며 리플리케이션된 파티션을 팔로워(follower)라고 부른다. 흔히 마스터, 미러라고 불리는 것이 카프카에서는 각각 리더, 팔로워와 같다.
프로듀서는 모든 리플리케이션(파티션)에 메시지를 보내는 것이 아니라, 리더에게만 메시지를 보낸다. 컨슈머도 리더에게서만 메시지를 가져온다.
리더의 메시지는 복제를 통해 팔로워에게 복제된다.이슈 등 문제상황이 생겨서 리더가 제 역할을 하지 못하면, 기존의 팔로워가 리더로 승격된다.
리더와 팔로워는 ISR(In Sync Replica)라는 논리적 그룹으로 묶여 있으며, 이를 통해 복제 등 여러 동작이 이루어진다. ISR 리스트는 주키퍼에 저장되어 있다.
리더에포크(Leader Epoch)
: 파티션이 복구 동작을 할 때 메시지의 일관성을 유지하기 위해서 이용 (오프셋 등을 내부적으로 이용하여 일관성 유지)
컨트롤러
: 파티션의 ISR 리스트에서 리더를 선출하는 브로커. 브로커가 다운되면 새로운 리더를 선출한다.
카프카에서 전송한 메세지는 어디에 저장이 될까요?
프로듀서를 이용해 보낸 메세지는 토픽의 파티션 0에 저장되어 있습니다
이처럼 프로듀서에 의해 브로커로 전송된 메세지는 토픽의 파티션에 저장되며, 각 메세지들은 세그먼트(segment) 라는 로그 파일의 형태로 브로커의 로컬 디스크에 저장되게 됩니다.
오프셋이란, 각 파티션마다 메시지가 저장되는 위치, consumer에서 메시지를 어디까지 읽었는지 저장하는 값 이라고도 볼 수 있다.
당연히 오프셋 값은 '파티션 내에서' 고유하고, 순차적으로 표기된다.
테이블의 pk (id) 개념과 비슷하다고 볼 수 있다.
컨슈머가 메세지를 어디까지 읽었는지 저장하고 있기 때문에 다음에 읽을 메시지 정보를 쉽게 알 수 있다.
예를 들어, 현재 offset = 3이라면, 컨슈머가 0~2까지 메시지를 읽은 것이고 다음에 읽어야 하는 메세지 정보는 3번 이라는 것을 의미한다.
이러한 offset을 통해 데이터의 순서가 보장되는 것이다.
위 그림과 같이 현재 offset은 4이며 다음 읽을 메시지는 5라는 것을 알 수 있습니다.
카프카에서 리플리케이션(replication) 이란 각 메세지들을 여러 개로 복제해서 카프카 클러스터내 브로커들에 분산시키는 동작을 의미 합니다.
💡 이러한 리플리케이션 동작 덕분에 하나의 브로커가 종료 되더라도 카프카는 안정성을 유지 할 수 있습니다.
토픽 명령어 중 replication-factor 옵션은 카프카내에서 몇개의 리플리케이션을 유지하는지를 설정하는 옵션 입니다.
토픽 생성시 --replication-factor 3 으로 지정하였기 때문에 원본은 포함하여 총 3개의 replication 이 있음을 의미 합니다.
위의 그림에서 test-overview01 토픽은 설정된 --replication-factor 옵션 값에 의해서 각 브로커에 배치된 상태를 보여주는 것 입니다.
그리고 조금더 정확하게 말해서 카프카에서 토픽이 리플리케이션이 된 것이 아니라 토픽의 파티션이 리플리케이션(복제)가 된 것이라고 표현할 수 있습니다.
replication-factor의 값이 높아지면 안정성이 높아지지만, 그만큼 브로커의 리소스 사용이 많아지며,복제에 대한 오버헤드가 발생될 수 있으므로 적절한 팩터수를 설정해서 사용을 해야 합니다.
테스트나 개발환경 : 리플리케이션 팩터 수 1
운영(로그성 메세지로 약간의 유실 허용가능) : 리플레키이션 팩터 수 2
운영(유실 허용안됨) : 리플레키이션 팩터 수 3
분산 시스템은 네트워크 상에서 연결된 컴퓨터들의 그룹을 말하며, 단일 시스템이 갖지 못한 높은 성능을 목표로 구성하게 됩니다.
이러한 분산 시스템은 성능이 높다는 장점 이외에도 하나의 서버 또는 노드 등에 장애가 발생할 때 다른 서버 또는 노드가 대신 처리 하므로 장애 대응에 좋으며, 부하가 높을 경우에는 확장이 용이 하다는 장점도 있습니다.
카프카도 이와 같은 의미로 분산 시스템이므로 최초 구성한 클러스터에서 브로커를 추가 하는 방식으로 확장이 가능 하며 카프카 브로커 추가는 온라인 상태에서 매우 간단하게 추가 할 수 있습니다.
이처럼 확장이 용이 하다는 점이 카프카의 매우 큰 장점 입니다.
파티션을 통한 분산처리로 짧은 시간 내에 엄청난 양의 데이터를 컨슈머로 전송 가능 (High throughput message capacity)
높은 성능
서버에 장애 대응에 탁월 (Fault tolerant)
시스템 확장 용이 (Scalability), 이미 사용하고 있는 브로커가 있다고 해도 신규 추가 용이
카프카는 높은 처리량을 얻기 위해서 여러가지 추가된 기능 중에 대표적으로 페이지 캐시 의 이용 입니다.
운영체제는 성능을 높이기 위해 계속 진화하고 개선되고 있으며, 그중 대표적인것이 페이지 캐시의 활용 입니다.
카프카 역시 OS의 페이지 캐시를 활용하는 방식으로 설계가 되어있으며 페이지 캐시는 애플리케이션이 사용하지 않는 잔여 메모리를 활용하며, 이러한 페이지 캐시를 이용하면 디스크 I/O 에 대한 접근이 줄어들므로 성능을 높일 수 있습니다.
카프카는 프로듀서 , 컨슈머 클라이언트들과 서로 통신하며, 이들 사이에서 수많은 메세지를 주고 받습니다.
이때 발생하는 수많은 통신을 묶어서 처리할 수 있다면 네트워크 오버헤드를 줄일 수 있으며 더욱 빠르고 효율적으로 처리 할 수 있습니다.
예를 들어, 온라인 상품 구매 프로세스에서 상품의 재고 수량 업데이트 작업과 구매 로그를 저장소로 보내는 작업을 한번 생각해봅시다.
상품의 재고 수량 업데이트 작업은 지연 없이 실시간으로 처리 되어야 하지만, 구매 로그를 저장소로 보내는 작업은 이미 로그가 서버에 기록되어 있기 때문에 실시간 처리 보다는 배치 처리를 이용하는 것이 더욱 효율적일 것 입니다.
카프카에서는 이와 같은 장점을 지닌 배치 전송을 권장하고 있습니다.
카프카는 메세지 전송시 좀 더 성능이 높은 압축 전송을 사용하는 것을 권장 합니다.
카프카에서 지원하는 압축 타입은 gzip , snappy , lz4 , zstd 등 입니다.
압축만으로도 네트워크 대역폭이나 회선 비용을 줄일수 있으며 앞에 설명한 배치 전송과 결합해 사용한다면 더욱 높은 효과를 얻게 됩니다.
파일 하나를 압축하는 것보다 비슷한 파일 10개, 혹은 20개를 압축하는 쪽의 효율이 더욱 좋기 때문 입니다.
압축 타입에 따라서 조금씩 특색이 있으며, 일반적으로 높은 압축률이 필요한 경우면 gzip 이나 zstd 를 권장하고, 빠른 응답속도가 필요하다면 lz4 나 snappy 를 권장 하고 있습니다.
카프카는 앞서 설명한 것 처럼 분산 시스템이기 때문에 하나의 서버나 노드가 다운 되어도 다른 서버 또는 노드가 대신하여 안정적인 서비스가 가능하게 합니다.
이러한 고가용성을 보장하기 위해서 카프카는 리플리케이션(복제) 기능을 제공 하고 있으며, 토픽 자체를 복제하는 것이 아닌 토픽의 파티션을 복제를 하는 방식으로 합니다.
토픽을 생성할 때 옵션으로 리플리케이션 팩터 수를 지정할 수 있으며, 이 숫자에 따라서 리플리케이션들이 존재하게 됩니다.
원본과 리플리케이션을 구분하기 위해서 카프카에서는 리더(leader) 와 팔로워(follower) 라고 부릅니다.
위의 표는 리플리케이션 팩터 수에 따른 리더와 팔로우 수의 관계를 보여주고 있습니다.
표에서와 같이 리더의 숫자는 1을 유지 하게 되고 리플리케이션 팩터의 수에 따라서 팔로워 수만 증가하게 됩니다.
팔로워 수가 많다고 딱히 좋은 것은 아닙니다 왜냐하면 팔로워의 수만큼 결국 브로커의 디스크 공간도 소비되기 때문 입니다. 그래서 적절한(이상적인) 리플리케이션 팩터 수를 유지해야하며 일반적으로는 3으로 구성하도록 권장되고 있습니다.
리더(leader) 는 프로듀서, 컨슈머로 부터 오는 모든 읽기 와 쓰기 요청을 처리하며, 팔로워는 오직 리더로 부터 복제를 하게 됩니다.