Kafka 기본 개념 톺아보기
글또(글쓰는 또라이) 9기 활동을 하고 있습니다. 글쓰는 습관을 만들고, 다양한 사람들을 만날 수 있어서 아주 만족하면서 활동하고 있는데요. 이번엔 유데미 강의를 들을 수 있는 기회가 있어, 평상시 궁금했던 카프카(Kafka)에 대한 강의(Apache Kafka 시리즈 – 초보자를 위한 아파치 카프카 강의 v3)를 들어봤습니다. 카프카에 대한 기본적인 개념부터, 주키퍼를 사용해 카프카를 운영하는 법, 주키퍼 없이 카프카 쓰기, CLI, Producer-Consumer 데모, 확장 API 와 실제 상용 환경에서 도움이 되는 내용 약간까지 커버하고 있어 만족스러웠습니다.
그 중, 제일 처음에 나오는 카프카에서 사용되는 개념들을 정리해봤습니다.
topic
topics
(이하 토픽) 는 데이터 스트림을 카프카에서 부르는 이름입니다. 우리가 흔히 사용하는 RDB에서의 table
과 유사합니다. 필요한 만큼 많이 생성 가능하고, 각 토픽은 name
으로 식별합니다. 토픽에는 그 어떤 종류의 메세지 포멧도 사용 가능하고, 메세지의 흐름(시퀀스)를 data stream
이라고 부릅니다. RDB의 table
과는 다르게, 토픽 안에서의 쿼리는 불가합니다. 대신 Kafka Producer가 데이터를 보내고, Kafka Consumer가 데이터를 읽도록 사용합니다.
Partitions and offsets
각 topic
은 Partitions
(이하 파티션)로 쪼개집니다. 각 파티션 안의 메세지는 순서가 있고, 증분 ID를 가집니다. 이게 바로 Offset
입니다. 각 메세지의 오프셋은 파티션 안에서만 의미가 있습니다. 예를 들어 파티션 0에서의 오프셋 3은 파티션 1의 오프셋 3과는 다릅니다. 따라서 메세지 간 순서성은 파티션 안에서만 보장되고, 오프셋 값은 이전 메세지가 삭제되더라도 재사용되지 않습니다. 데이터를 넣을 때 key
를 지정하지 않는 이상, 랜덤한 파티션에 메세지가 저장됩니다.
각 카프카 토픽은 불변성을 가집니다. 일단 파티션에 기록되면 변경될 수 없습니다. 더해서, 데이터는 한정된 시간만 유지가 됩니다. 기본 값으로 1주간 유지되고, 설정은 변경이 가능합니다.
Producers
데이터를 만들어 내는(=카프카에 기록하는) Producer(이하 프로듀서)는 파티션의 집합으로 구성 된 토픽에 데이터를 기록합니다. 프로듀서는 메세지를 기록할 때 어떤 파티션에 메세지를 기록할 지 알고(=지정)있습니다. 그 이전에, 어떤 카프카 브로커가 그 파티션을 가지고 있는지도 알고 있습니다. 만약 작성 시, 카프카 브로커가 실패할 경우 프로듀서가 자동으로 복구 시도합니다. 각 파티션이 쪼개져 있으므로, 자연스럽게 로드밸런싱이 됩니다.
Message Keys
프로듀서는 메세지에 key
를 넣어 전송합니다.(String, Number, Binary…) key=null일 경우, 데이터는 Round Robin 알고리즘으로 파티션에 작성이 되고, 만약 key≠null일 경우 키를 해싱해 한 파티션을 지정하여 해당 키의 데이터는 항상 같은 파티션으로 전송됩니다.
기본적으로 사용되는 default kafak partitioner에서는 해싱에서 murmur2 algorithm
을 사용합니다.
targetPartition = Math.abs(Utils.nurnur2(keyBytes)) % (numPartitions -1 )
특정 필드에 한해 순서가 지정되어야 할 때 보통 key
를 사용합니다.
Message 구조
프로듀서가 만드는 메세지는 key-value 값과 메세지가 저장되는 파티션+오프셋 값 및 기타 메타데이터가 저장됩니다.
- Key(binary) - null일 수 있음
- Value(binary) - null일 수 있음
- Compression Type
- none, gzip, snappy, lz4, zstd…
- headers(key-value 쌍) - optional
- partition + offset
- Timestamp
Consumers
메세지를 가져다 쓰는 Consumer(이하 컨슈머)는 name으로 식별되는 토픽에서 데이터를 읽어옵니다.(보통 Pull model이라 부르는 형태죠) 데이터는 각 파티션에서 낮은 오프셋 - 높은 오프셋 순서로 읽어옵니다.
Consumer groups
어플리케이션에 있는 컨슈머는 consumer group
(이하 컨슈머 그룹, 그룹)단위로 데이터를 읽습니다. 컨슈머 그룹 내 각 컨슈머는 그룹 내에서 서로 다른 파티션에서 데이터를 읽습니다. 중복되는 파티션이 없게 각 컨슈머가 파티션을 맡습니다.(XOR-상호배제) 만약 그룹 내 컨슈머가 파티션보다 많을 경우, 몇 컨슈머는 비활성화 상태로 있게 됩니다. 한 토픽에 여러 컨슈머 그룹이 붙어 있을 수 있고, 만약 필요한 경우 컨슈머의 속성 중 group.id
를 사용해 컨슈머 그룹을 지정할 수 있습니다.
Consumer Offsets
카프카는 각 컨슈머 그룹이 읽고 있던 오프셋을 저장하고 있습니다. __consumer_offsets
토픽을 사용해, 컨슈머 그룹 내 컨슈머가 카프카로부터 데이터를 가져오게 되면, 일정 주기마다 오프셋을 커밋합니다. 여기서 짚고 갈 것은 컨슈머 그룹에서 직접 기록하지 않고 카프카 브로커가 __consumer_offsets
에 기록한다는 점입니다. 만약 컨슈머가 죽게 되면, 커밋되어 있는 오프셋을 확인하고 그 위치부터 다시 읽어올 수 있습니다.
Delivery semantics for consumers
기본적으로, 자바 컨슈머는 자동적으로 offset을 커밋합니다. 이것을 수동으로 변경한다면, 크게 세가지 방법을 생각할 수 있습니다. 첫번째로, “최소 한 번”(At Least Once) 같은 경우 메세지가 처리되고 난 뒤 오프셋을 커밋합니다. 처리가 제대로 되지 않을 경우 메세지는 한번 더 읽힙니다. 이 경우, 메세지의 중복 처리 가능성이 있어, 처리 과정이 멱등성(Idempotent)있도록 구성해야 합니다.
두 번째로 “최대 한 번”(At Most Once)의 경우, 메세지가 수신되자마자 오프셋을 커밋합니다. 처리가 제대로 되지 않을 경우, 메세지가 유실될 가능성이 있습니다.
마지막으로, “딱 한번”(Exactly Once)가 있습니다. 이 경우는 좀 복잡한데, 카프카 → 카프카 구성일 경우 Transactional API를 사용합니다.(Kafka Streams API 사용하면 더 편함) 카프카 → 외부 시스템 구성일 경우, 멱등성 있는 컨슈머를 사용해야 합니다.
Kafka Brokers
Kafka Cluster
는 여러 Kafka Broker
(server)로 구성됩니다. 각 브로커는 ID(정수)로 구별되고, 각 브로커는 토픽당 최대 한 파티션을 가지고 있습니다.
카프카 클라이언트가 어떤 브로커에 접속하고 나면, 클러스터의 정보를 받아 전체 클러스터에 접속됩니다. 이 경우 최초 연결되는 브로커를 Bootstrap Broker
라고 합니다. Kafka Broker Discovery라고 부르는 이 과정에서, 각 브로커들은 모든 브로커에 대한 정보와 토픽, 파티션 정보들(메타데이터)을 가지고 클라이언트에게 넘겨주게 됩니다.
3개 브로커로 시작해 큰 클러스터는 100개가 넘는 브로커를 가질 수 있습니다.
Kafka Replication Factor
토픽 내 각 파티션이 얼마나 많은 수의 브로커에 뿌려지는지에 대한 숫자가 Replication Factor입니다. Replication Factor가 2일 경우, 어떤 브로커 안에 있는 파티션이 다른 한 브로커에도 복제되어 구성됩니다.
토픽들은 Replication factor를 1보다 큰 값을 가져야 합니다. 대개 2~3정도의 값을 가지게 구성을 하고, 그렇게 구성해야 어떤 브로커가 동작하지 않을 때 다른 브로커가 해당 데이터를 처리할 수 있습니다.
Leader for a partition
어느 순간이든, 어떤 한 브로커만이 특정 파티션에 대해 리더 역할을 합니다. 프로듀서의 경우, 파티션의 리더 브로커에만 데이터를 보낼 수 있습니다. 각 파티션은 한 개의 리더와 여러개의 ISR(In-sync Replica)를 가집니다.
기본적으로 컨슈머는 프로듀서와 동일하게 리더 브로커에서만 읽어옵니다. 다만, Kafka v2.4+부터 사용 가능한 Kafka Consumers Replica Fetching을 사용하면 가장 가까운(Latency 가 낮은) 레플리카에서 읽어 올 수 있습니다. 이 경우 Latency를 줄이고, 클라우드 환경에서 네트워크 비용을 줄일 수 있는 장점이 있습니다.
강의를 계속해서 듣고 있는 중인데, 개념에서부터 실습-상용환경까지 생각보다 커버하는 내용이 많아 만족스럽습니다. 요즘 데이터 처리나 서비스 간 통신에서 정말 많이 사용하고 있는 것으로 알고 있는데, 카프카에 대해 파는게 조금 늦은게 아닌가 싶네요. 지금 당장 업무에서 사용중이지는 않지만, 그래도 알아두면 다른 메세지 큐를 사용하거나 다른 매니지드 카프카 서비스를 써먹을 때 도움이 될 것 같아 강의 내 다른 내용도 정리해보려 합니다!