이번 포스팅에서는 Kafka에 대해 심플하게 짚고 넘어가려고 합니다.
Apache Kafka는 2011년도 LinkedIn 에서 사내 중앙집중형 분산 메세징 시스템으로 시작하여 현재는 대표적인 실시간 데이터 스트리밍 플랫폼으로 자리잡았습니다.
하위 프로젝트로는 KSQL과 Kafka Streams를 가지고 있습니다.
KSQLKafka StreamsApache Kafka와 같은 메세징 시스템(ActiveMQ, RabbitMQ, …)들은 시스템 내부에서 각 어플리케이션 간의 메세지 교환을 위해 만들어졌습니다. 이런 메세징 시스템은 아래와 같은 특징들을 지닙니다.
느슨한 결합으로 이루어져 있습니다. 독자적인 시스템과 프로세스로 이루어져 있어 종속성이 약합니다.사실
Ack나Exactly Once등 정말 많은 내용들이 있지만 카프카 핵심 가이드(대규모 실시간 데이터와 스트림 처리) 포스팅에서 제대로 다루도록 하겠습니다.
%%{ init : { "theme" : "dark", "flowchart" : { "curve" : "stepBefore" }}}%%
graph LR
PD1([Producer 1])
PD2([Producer 2])
subgraph KC[Kafka Cluster > Broker]
subgraph TP3[Topic N]
PT1([Partition 1])
PT2([Partition 2])
...([. . .])
PTN([Partition N])
end
end
CS1([Consumer 1])
CS2([Consumer 2])
CS3([Consumer 3])
%% Data Flow
PD1 -- message --> PT1
PD1 -- "message" --> PT2
PD2 -- "message" --> PTN
PT1 -. "message" .- CS1
PT1 -. "message" .- CS2
PT2 -. "message" .- CS1
PT2 -. "message" .- CS2
PTN -. "message" .- CS3
위 플로우차트는 mermaid를 활용하여 Kafka의 대략적인 동작방식을 나타낸 것입니다. 간단하게 요약하자면 Producer에서 broker로 메세지를 보내면, broker
는 이를 스트리밍 버스(Streaming Bus)와 같이 버퍼에 가지고 있다가 수많은 시스템에서 이 메세지들을 consume해 가게 됩니다. 또한 이런 kafka 동작을 보조하는 분산코디네이터인 zookeeper가 있습니다.
앞으로 다루게 될 카프카 포스팅에서는 이를 대체하는 KRaft 에 대해서도 함꼐 알어보도록 하겠습니다.
본론으로 돌아와서, Kafka를 이루는 구조적 특징을 몇가지 정리하고 넘어가겠습니다.
Topic(토픽)에 저장합니다. 이 Topic은 논리적인 개념의 메세지 주소를 의미하며, 사용자는 원하는 토픽(메세지 주소)로 메세지를 발송하고, Consumer는 이로부터 메세지를 수령할 수 있습니다.Offset은 Partition안에서 데이터의 위치를 표시하는 값을 의미합니다. Partition에 데이터가 저장되면 Kafka는 해당 Partition 안에서 위치값을 지정하고, Consumer는 Polling 방식으로 이 Offset(위치값)을 읽어 메세지를 수신하게 됩니다.지난 카프카 도서들(실전 카프카 개발부터 운영까지, ]ㅡ,/ 아파치 카프카 애플리케이션 프로그래밍 with 자바)에 이어서 이번에 따끈따끈한 신판:카프카 핵심 가이드(대규모 실시간 데이터와 스트림 처리) 이 나와 제대로 읽어보며 포스팅을 진행하려고 합니다.
그러면 지금까지 배운 내용을 Java로 어떻게 구현할 수 있는지 확인해봅시다.
해당 공식문서 를 확인하면 Kafka의 세세한 Config 정보까지 전부 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Producer API Sample Code
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.ACKS_CONFIG, "all");
props.put(ProducerConfig.RETRIES_CONFIG, Integer.valueOf(1));
props.put(ProducerConfig.LINGER_MS_CONFIG, Integer.valueOf(1));
// Consumer API Sample Code