
참고 포스팅 및 영상

링크드인(Linked-in)에서 개발되었으며, 2011년에 오픈 소스화 되었습니다.
kafka 도입 이전에는 두 애플리케이션 간에 데이터를 주고 받기 위해 직접 연결된 end-to-end(E2E) 연결 방식의 아키텍처를 사용했습니다.
E2E 구조는 Source App. 과 Target App. 간에 깊은 결합도와 두 App.이 연결된 전송 파이프라인의 복잡성으로 인해 배포 및 장애에 대응이 어려워지고, 프로토콜 포맷의 파편화를 야기했습니다.
💡 Source App. & Target App.
Source App. 은 데이터의 출처이자, 데이터를 전소하는 주체이고, Target App. 은 데이터를 받고자 하는 객체입니다.
kafka는 이러한 문제들을 해결하고자 개발된 분산 스트리밍 메시징 시스템입니다.

Kafka를 도입으로 Source App.에서 데이터 타입에 상관없이 Kafka로 데이터를 전송하면 Target App.은 필요한 데이터를 Kafka에서 가져오게 되는 형태로 데이터 전달이 수행됩니다.(느슨한 결합 형태)
Kafka에 전달된 메시지들은 높은 처리량을 위해 최적화 되어 쌓이게 됩니다.
카프카는 멀티 클러스터링 구조로 여러 대의 카프카 브로커로 구성이 가능하여 처리량이 많아질 경우 scale-out이 가능한 구조로 되어 있습니다.

카프카 클러스터 내부에 카프카 브로커가 있습니다.
브로커 내부에 Topic이라는 단위가 존재하고, Topic 내 공간을 나눠놓은 단위를 파티션이라고 합니다. 각 파티션은 Queue의 형태를 가지고 있습니다.
실행되고 있는 kafka 애플리케이션 서버를 의미합니다.
일반적으로 3대 이상의 Broker로 구성하는 것을 권장합니다.
Apache Zookeeper를 연동 - 카프카 클러스터 코디네이터
역할 : 메타데이터(Broker ID, Controller ID 등) 저장
Controller 정보 저장
장애에 대한 복구
n 개 Broker 중 1 대는 Controller(리더) 기능을 수행
Controller 역할
각 Broker에게 담당 파티션 할당
Broker 정상 동작 모니터링 관리
카프카에서 다양한 데이터가 들어갈 수 이쓴ㄴ 공간을 말합니다.
하나의 브로커 내에 다수의 Topic 생성이 가능합니다.
토픽별로 네이밍이 가능하며, Topic 별로 담을 데이터 종류에 따라 구분함으로써 유지 보수성을 높일 수 있습니다.
하나의 Topic은 여러 개의 Partition으로 구성될 수 있습니다.(첫번째 Partition은 0번부터 시작)
Partition의 구조는 Queue의 구조와 동일하며, Producer로부터 들어온 데이터를 앞에서부터 차례대로 쌓습니다.
Consumer(데이터를 가져가는 역할)는 partition 내부를 확인 후 데이터가 들어올때까지 일정시간 대기합니다.
Consumer가 Partition 내 데이터를 읽어가도, 안에 있는 데이터는 삭제되지 않습니다. 이를 통해 다른 Consumer group의 Consumer에서 동일한 데이터를 0번부터 가져갈 수 있습니다.
⭐ 왜 파티션 안에 데이터는 사라지지 않을까?
이는, 동일한 데이터를 2번 이상 처리할 수 있도록 구현하기 위해서 입니다.
⭐ 파티션이 하나 더 늘어나게 되면 어떻게 동작할까?
Partition 2개 이상부터는 key값을 설정할 수 있게됩니다.
- key가 null 값이고, 기본 파티셔너를 사용하는 경우 → Round Robin 방식으로 메시지 할당
- key가 있고, 기본 파티셔너를 사용하는 경우 → 키의 해시를 구하고, 특정 파티션과 프로듀서를 1대1매칭.
⭐ 파티션 내 레코드는 삭제되지 않는 것인가?
아닙니다. 이는 옵션에 따라 다릅니다.
- log.retention.ms : 최대 레코드 보존기간
- log.retention.byte : 최대 레코드 보존크기
⚠️ 주의사항
여기서 주의할 점은 Partition은 한번 생성함면, 다시 줄이기가 힘들게 됩니다.(appendOnly)
이러한 위험을 감수하고도 partition을 늘리는 이유는 partition과 consumer를 늘려서 데이터 처리량을 늘릴 수 있도록 하기 위함입니다.
다음의 3가지 개념은 Kafka 내 핵심 개념인 고가용성(fault tolerant) 유지에 필요한 중요개념입니다.
Kafka Broker : 카프카가 설치된 서버 단위를 의미하며, 일반적으로 3개 이상의 Broker 사용을 권장합니다.
이러한 Borker들을 묶어서 Kafka Cluster라고 합니다.
partition 1, replication 1인 topic이 있고, broker가 3인 경우, 3개의 브로커 중 한 곳에 Topic 정보가 저장되어 있음을 의미합니다.
Kafka Replication : partition의 복제를 의미합니다.
partition 1, replication 1 인 topic 설정인 경우, 하나의 broker 안에 단일 파티션이 존재하것을 의미합니다.
partition 1, replication 2 인 topic 설정인 경우, 하나의 broker 안에 단일 파티션이 존재하고, 다른 하나의 broker에 복제한 파티션이 존재하는 것을 의미합니다.
이처럼 partition을 복제해놓는 이유는 고가용성을 위해서 입니다.
만약, 하나의 브로커에 원본 파티션으로 관리하다가 해당 브로커가 장애가 발생하면, 데인터 유실이 발생하게 됩니다.
이를 방지하고자 2개 이상의 replication을 생성하여 Leader partition 장애 시, Follower가 이를 계승하도록 구현하여 데이터의 유실을 막습니다.
원본 파티션과 복제품을 구분하기위해 별도의 명칭을 사용합니다. 원본 파티션 - Leader Partition, 복제품 - Follower Partition.
ISR(In Sync Replication) : Leader와 Follower를 합쳐 하나의 ISR이라고 말합니다.
Leader와 Follower의 차이는 Leader에서 Topic으로 들어온 데이터를 처음 받는 역할을 합니다.
여기서 드는 의문은 고가용성을 높이기 위해서 replication을 최대한 많이 만들수록 좋은 것이 아닌가라는 생각이 들 수 있습니다.
하지만, replication의 증가는 결국 Kafka Broker의 리소스 사용량 증가로 이어져, 데이터 처리 성능에 영향을 미치게 됩니다.
따라서, Kafka에 들어오는 데이터량과 각 partition의 retention date를 고려하여 replication 갯수를 생성하는 것이 좋습니다. - 일반적으로 3개 이상의 브로커 사용 시, replication은 3개를 권장합니다.
Kafka는 TCP 기반의 프로토콜을 고성능으로 커스텀하여 사용하는 서버와 클라이언트로 구성된 분산 시스템입니다.
이로 인해, Kafka 안에서도 ack이라는 용어가 나오게 됩니다.
Producer(레코드 제공자)는 상세옵션으로 ack이라는 것이 있습니다.
이는 3개의 종류로 나뉩니다. 0, 1, all
ack - 0 : Producer는 Leader Partition으로 레코드를 전달한 뒤 응답을 받지 않습니다.
ack - 1 : Producer는 Leader Partition으로 레코드를 전달한 뒤 Leader에 레코드가 저장됐는지만 응답 받습니다.
ack - all : Producer는 Leader Partition으로 레코드를 전달한 뒤 Leader에 레코드 저장 및 Replication에 복사된 레코드가 있는지 응답 받습니다.
현업에서는 상황에 맞게 각 옵션을 활용하면 되겠습니다.
Producer가 데이터 전달 시, 반드시 Partitioner를 통해서 Kafka Broker로 전달됩니다.
Partition는 Topic 내 어떤 Partition에 레코드를 넣을지 결정해줍니다.
이는 레코드에 포함된 메시지 key 또는 메시지 value에 따라서 위치가 달라집니다.
Producer 사용 시 별도로 커스텀하지 않으면, UniFormStickey Partitioner 로 설정됩니다.
해당 파티셔너는 메시지 키 유무에 따라 다르게 동작합니다.
메시지 키 X
Round Robin 방식으로 파티션에 레코드가 담기는데, Producer가 들어오는 데이터를 배치 로 최대한 묶어 모아서 파티션으로 데이터를 보내줍니다.
메시지 키 O
파티셔너에 의해서 키를 특정 해시값으로 인코딩해준 뒤, 특정 파티션에 1 대 1로 매칭해줍니다.
만약, 2개 이상의 파티션에 매칭되는 키가 2개 존재하는 경우에 각 레코드의 키에 맞는 파티션으로 들어가게 됩니다. 니를 통해서 동일한 파티션에 들어간 레코드 간에는 순서가 보장된다는 장점이 있습니다.
주의할 점은 파티션이 하나 더 생성될 경우, 파티셔너는 다시 라운드 로빈 방식으로 파티션에 담게 됩니다. 따라서, 이에 주의하여 파티션을 생성해줘야 합니다.
파티셔너는 커스텀이 가능합니다.
Kafka에서는 커스텀 파티셔너를 만들 수 있도록 Partitioner 라는 인터페이스를 제공합니다.
파티셔너 인터페이스를 사용해서 커스텀 파티셔너를 만들면 메시지 키, 값, 토픽 이름에 따라서 어느 파티션에 데이터를 보낼지 정할 수 있습니다.