카프카(Kafka) 란?

카프카 홈페이지에 들어가 보면 카프카를 고성능 분산 이벤트 스트리밍 플랫폼이라고 소개하고 있다.
또한 Fortune 100 기업 중 80프로 이상이 카프카를 사용한다고 한다. 아래의 이모티콘에서 볼 수 있듯
다양한 업종에서 카프카를 사용하고 있다.
카프카의 구조

카프카의 구조를 간단히 도식화하면 위와 같은데 프로듀서와 컨슈머는 메시지(이벤트)를 기반으로
통신한다. 프로듀서는 카프카 클러스터에 메시지를 저장하고, 컨슈머는 카프카 클러스터에서 메시지를
가져온다. 카프카 클러스터를 이루고 있는 브로커는 각각 하나하나가 서버라고 생각하면 되는데
이런 브로커들이 모여 카프카 클러스터를 형성한다.
카프카 클러스터를 관리하기 위해 주키퍼 클러스터(앙상블)가 필요하다 (Kafka 2.8.0 버전부터 주키퍼 없이도 카프카를
구동할 수 있도록 KRaft모드가 추가되었다) 이때 주키퍼 또한 클러스터로 구성되는데
그 이유는 주키퍼가 카프카 클러스터를 관리하기 때문에 주키퍼 또한 장애에 대응할 수 있어야 하기 때문이다.

토픽(topic)이란 메시지를 구분하는 단위인데 파일시스템에서의 폴더와 유사하다고 생각하면 된다.
하나의 토픽은 한 개 이상의 파티션(partition)으로 구성되는데 이때 파티션은 메시지를 저장하는 물리적인 파일이다.
프로듀서는 카프카에 메시지를 저장할 때 어떤 토픽에 저장해 달라고 요청하고, 컨슈머는 어떤 토픽에서 메시지를 읽어온다고
요청하게 된다.

파티션은 append-only 파일이다. 즉 추가만 가능하다.(카프카가 일부를 삭제하기도, 축약하기도 하지만 기본적으로는
append-only 파일이다) 이때 각 메시지의 저장 위치를 오프셋(offset)이라고 한다. 프로듀서가 메시지를 저장하면 저장된
메시지들은 차례대로 offeset0, offset1, offset2, ... 같이 오프셋 값을 가지게 된다. 이때 append-only 파일 이므로 메시지는
파티션의 맨 뒤에 추가된다. 컨슈머는 이 오프셋을 기준으로 메시지를 순서대로 읽는다. 예를 들어 어떤 컨슈머가 특정 파티션의
3번 오프셋부터 데이터를 읽는다고 하면 3번 이상의 메시지만 읽을 수 있다. 그 앞에 있는 0,1,2 메시지는 읽지 않는다.
읽어 갈 때도 3,4,5,6 이런 식으로 순서대로 메시지를 읽어가게 된다. 이때 컨슈머가 읽어갔다고 해서 파티션에 저장된 메시지가
삭제되지는 않는다. (단 설정에 따라 일정 시간이 지난 뒤 삭제된다)

하나의 토픽이 여러 개의 파티션으로 나누어질 수 있는데 이때 프로듀서가 어떤 파티션에 저장 할까?
규칙은 간단한데 라운드로빈으로 돌아가면서 저장을 하거나 또는 키를 이용해서 파티션을 선택하게 된다.
프로듀서가 카프카에 메시지를 전송할 때 토픽의 이름뿐만 아니라 키도 지정할 수 있다.
키가 있는 경우 키의 해시값을 이용해서 저장할 파티션을 선택하게 된다. 따라서 같은 키를 갖는 메시지는
같은 파티션에 저장이 된다. 즉 같은 키를 갖는 경우 메시지의 순서가 보장된다.

컨슈머는 컨슈머 그룹에 속하게 되는데 컨슈머가 카프카 브로커에 연결할 때 자신이 어떤 그룹에 속해 있는지를
명시해야 한다. 이때 중요한 것은 하나의 파티션은 그룹당 하나의 컨슈머에만 연결이 가능하다. 즉 그림상 컨슈머 A 그룹에서
컨슈머 1이나 컨슈머 2중 하나만 topic1의 partition0에 연결될 수 있다. 따라서 하나의 그룹에 속해있는 컨슈머간에는
하나의 파티션을 공유할 수 없다. 따라서 한 컨슈머 그룹 기준으로 파티션의 메시지는 순서대로 처리된다.
카프카의 성능
카프카의 성능이 좋은 이유중 몇 가지는 아래와 같다.
파티션 파일은 OS페이지 캐시 사용
카프카에서는 파티션에 대한 파일 I/O를 메모리에서 처리한다. 일반적으로 파일 I/O를 디스크에 한다면 I/O 처리 속도로 인해
성능이 떨어지게 된다. 카프카는 페이지 캐시를 사용하는데 페이지 캐시란 처리한 데이터를 메인 메모리 영역(RAM)에 저장해서
가지고 있다가, 다시 해당 데이터에 대한 접근이 발생하면 disk에서 I/O처리를 하지 않고 메인 메모리 영역의 데이터를 반환한다.
순차 I/O

카프카는 데이터를 디스크에 기록할 때, 랜덤 액세스를 최소화하고 연속적으로 데이터를 기록하도록 설계되어 있다.
위의 표를 보면 알 수 있듯 Sequential disk 접근은 Random 메모리 접근보다도 더 빠른 속도를 보여준다.
이를 통해 카프카는 대용량 데이터를 빠르게 처리할 수 있다.
Zero-Copy


일반적으로 네트워크를 통해 데이터를 전달하는 과정은 왼쪽과 같다.
OS는 디스크로부터 데이터를 읽어 커널 영역의 page cache에 저장한다 → 애플리케이션이 page cache의 데이터를
사용자 영역으로 읽어온다 → 애플리케이션은 커널 영역에 있는 socket buffer로 데이터를 쓴다 → OS는 socket buffer에
있는 데이터를 NIC Buffer로 복사하고 네트워크를 통해 전송한다.
여기서 OS가 제공하는 sendFile 함수를 사용하면 커널 영역의 page cache에서 NIC Buffer로 직접 복사가 가능해
더욱 효율적으로 데이터를 전송할 수 있다.
컨슈머 추적을 위해 브로커가 하는 일이 비교적 단순
보통의 메시징 시스템이 메시징을 필터링하거나, 메시지를 재전송하는 등의 작업을 하는데 카프카 브로커는
이런 작업들을 하지 않고 프로듀서와 컨슈머가 직접 한다. 하는 일이 상대적으로 적기 때문에 성능이 더 빨라질 수
있다.
묶어서 보내기, 묶어서 받기(batch)
프로듀서는 일정 크기만큼 메시지를 모아서 전송할 수 있고, 컨슈머는 최소 크기만큼 메시지를 모아서 조회 가능하다.
따라서 낱개로 매번 네트워크를 통해서 보내고 받는 게 아니라 모아서 보낼 수 있기 때문에 처리량이 증가한다.
처리량 증대(확장)가 쉬움

장비의 용량이 한계가 있다면 브로커와 파티션을 추가하면 되고, 컨슈머가 느리면 컨슈머를 추가해 주거나
파티션을 추가해 주면 된다. 이런 식으로 수평 확장이 용이한 구조를 가지고 있기 때문에 처리량을 늘리는 게
상대적으로 쉽다.
장애 대응

카프카는 장애 대응을 위해 리플리카를 사용한다.
리플리카는 파티션의 복제본이고 복제수(replication factor) 만큼 파티션의 복제본이 각 브로커에 생긴다.
이때 파티션 중 하나는 리더가 되고 나머지는 팔로워가 된다. 프로듀서와 컨슈머는 리더를 통해서만 메시지를 처리하게 되고,
팔로워는 리더에서 데이터를 복제해 오는 역할을 수행하게 된다. 이때 만약 리더가 있는 브로커에 장애가 발생하면
팔로워 중 하나가 리더가 된다.
참고
https://www.youtube.com/watch?v=0Ssx7jJJADI
https://parkcheolu.tistory.com/261
https://medium.com/sjk5766/kafka-disk-i-o%EA%B0%80-%EB%B9%A0%EB%A5%B8-%EC%9D%B4%EC%9C%A0-899c4da5084
'Infra' 카테고리의 다른 글
클러스터와 노드 개념 (0) | 2025.03.24 |
---|---|
Nginx 알아보기 (0) | 2025.03.04 |
도커(Docker) 알아보기 (1) | 2024.10.20 |