백엔드 데이터 인프라 121편. Kafka Streams 입문 — 별도 cluster 가 아닌 라이브러리 모델·Java/Scala 애플리케이션·exactly-once·Kafka 내장 통합·Spark Streaming·Flink 와의 결정적 차이까지 풀어쓴 학습 노트. Part 5-10 Streams 시작.
이 글은 백엔드 데이터 인프라 시리즈 130편 중 121편이에요. Part 5-9 Connect 까지 끝났다면, 이번 121편부터는 Part 5-10 — Kafka Streams (9편). 첫 글은 Kafka Streams 의 정체성·왜·Spark/Flink 와 어떻게 다른가.
Kafka Streams가 어렵게 느껴지는 이유
Stream processing(실시간 데이터 흐름 처리) 영역은 도구가 여러 개라 헷갈려요. Spark, Flink(저지연 스트림 엔진), Kafka Streams, Samza(분산 스트림 처리 프레임워크) 가 각자 다른 모델로 같은 문제를 풀고 있거든요. 그래서 왜 굳이 Kafka Streams 인지가 한 번에 안 잡혀요.
첫째, 라이브러리 vs 클러스터 모델 차이가 있어요. Spark·Flink 는 별도 cluster 를 두고 거기에 job 을 던지는 구조고, Kafka Streams 는 내 애플리케이션 안에 라이브러리로 들어가요.
둘째, KStream vs KTable 개념. Stream-table duality(스트림과 테이블이 같은 데이터의 두 관점) 가 처음 보면 추상적이에요.
셋째, 언제 Kafka Streams 를 쓰고 언제 Spark·Flink 를 쓸지 기준이 안 잡혀요.
이 글에서 정체성·핵심 개념·도구 비교까지.
Kafka Streams 의 정체성
"Kafka Streams is a client library for building applications and microservices, where the input and output data are stored in Kafka clusters."
핵심: 별도 cluster 없는 client 라이브러리예요.
- Java/Scala 애플리케이션 코드 안에 포함
- 자체 microservice 로 배포
- Kafka cluster 만 별도 인프라
[Kafka Cluster]
↑↓
[My Microservice (Spring Boot + kafka-streams)]
- Stream Processing 로직
- 자체 운영
Spark·Flink 처럼 별도 cluster 를 운영할 부담이 없어요.
핵심 장점
- Elastic·Scalable·Fault-tolerant — Kafka 의 partition 기반 자동 분산
- Containers·VMs·Bare metal·Cloud — 일반 Java 애플리케이션 처럼 배포
- Exactly-once Semantics (EOS) — 정확히 한 번 처리 보장. 88·112편 EOS 모델
- No separate cluster — Kafka 만 있으면 됨
- Kafka 통합 — security·monitoring 모두 자연스러움
- Mac/Linux/Windows — 개발 환경 자유
사용 사례 — Real-world
- New York Times — 출판된 content 를 실시간 distribution
- Pinterest — 광고 예산 실시간 처리
- Rabobank — Fraud detection(이상 거래 탐지)
- Trivago — 호텔 검색 데이터 enrichment(보강)
- Zalando — 추천 시스템
대부분 실시간 ETL(추출·변환·적재)·이벤트 보강·집계·탐지 영역이에요.
라이브러리 모델 vs 클러스터 모델
Spark Streaming·Flink (Cluster 모델)
[Spark/Flink Cluster] ── 별도 인프라 ──
│
│ submit job
↓
[Stream Processing Jobs]
│
│ source/sink
↓
[Kafka], [DB], [HDFS], [S3]
장점:
- 매우 강력 (batch + streaming, ML, SQL)
- 풍부한 생태계 (Kafka 외 다양한 source/sink)
- 대규모 (수천 노드)
단점:
- 별도 cluster 운영 부담 — 인프라 + 모니터링 + upgrade
- Job 제출·관리 (YARN(하둡 자원 관리자)·Kubernetes 등)
- Deploy 복잡
Kafka Streams (라이브러리 모델)
[My Spring Boot Microservice]
- kafka-streams.jar
- Stream 로직
- 자체 deploy
│
│ source/sink
↓
[Kafka Only]
장점:
- 단순 — Java 애플리케이션처럼 배포
- 운영 부담 ↓ (Kafka 만)
- 마이크로서비스 친화
단점:
- Kafka 외 source/sink X (Connect 와 결합 필요)
- 매우 큰 분산 처리 어려움 (Spark·Flink 보다)
선택 가이드
| 시나리오 | 권장 |
|---|---|
| Kafka 안 데이터 + 마이크로서비스 | Kafka Streams |
| 대규모 분산 ETL + ML | Spark |
| 매우 낮은 latency + 복잡한 stream | Flink |
| Batch + Streaming 통합 | Spark / Flink |
| Connect + 가벼운 변환 | Kafka Streams (또는 SMT, 118편) |
대부분의 Kafka 중심 microservice 는 Kafka Streams 가 답이에요.
KStream vs KTable — 핵심 개념
KStream — record stream (이벤트 흐름)
KTable — changelog stream (현재 상태)
KStream
("user42", "login") at t=1
("user42", "purchase") at t=2
("user42", "logout") at t=3
모든 이벤트가 append-only(이어 붙이기만 함). 각 이벤트가 독립이에요.
KStream<String, String> events = builder.stream("user-events");
KTable
("user42", "online") at t=1 → 현재: online
("user42", "offline") at t=2 → 현재: offline
("user42", "online") at t=3 → 현재: online
각 key 의 최신 값만 의미. Compacted topic(키별 최신 값만 남기는 토픽) 과 자연스럽게 매칭.
KTable<String, String> userStatus = builder.table("user-status");
Duality
KStream → groupByKey().reduce() → KTable (집계로 상태 추출)
KTable → toStream() → KStream (상태를 다시 stream 으로)
같은 데이터를 두 가지 관점으로 보는 거예요. 이게 Stream-Table Duality.
가장 단순한 예제
StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> input = builder.stream("input-topic");
input
.filter((key, value) -> value.startsWith("important"))
.mapValues(value -> value.toUpperCase())
.to("output-topic");
KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();
// graceful shutdown
Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
5줄로 input topic → filter → uppercase → output topic 까지 끝나요. Stream 처리 시작.
DSL vs Processor API
Kafka Streams 는 추상화 단계가 두 개예요.
DSL (High-level)
input
.filter(...)
.mapValues(...)
.groupByKey()
.windowedBy(...)
.reduce(...)
.to(...);
DSL(도메인 특화 언어) 은 선언적이고 간단해서 90% 환경에 충분해요. 125편 깊이.
Processor API (Low-level)
Topology topology = new Topology();
topology.addSource("source", "input-topic");
topology.addProcessor("processor", MyProcessor::new, "source");
topology.addSink("sink", "output-topic", "processor");
세밀 제어·custom logic 가 필요할 때 써요. 126편 깊이.
핵심 Topology 개념
Topology = Source → Processor 들 → Sink
Topology(스트림 처리 흐름의 그래프 구조) 가 곧 processing graph 예요. Kafka Streams 가 이 graph 를 task 들로 쪼개 Kafka partition 에 매핑해요.
핵심 Use Cases (다음 편들에서 깊이)
- 단순 변환 — filter·map·flatMap (125편 DSL)
- 집계 — count·sum·aggregate (127편 stateful)
- Window 처리 — tumbling·hopping·session window (127편)
- Join — KStream-KStream·KStream-KTable·KTable-KTable (125편)
- Stateful processing — RocksDB(임베디드 키-값 저장소) local state store (127편)
- Interactive Queries — state 외부 query (127편)
학습 로드맵
Part 5-10 Streams 9편:
- 121 Intro (이 글) — 정체성·라이브러리 모델·KStream/KTable
- 122 Quickstart — 직접 만져보기
- 123 Core Concepts — Topology·Task·Thread·Partition 매핑
- 124 Write & Run App — Spring Boot 통합·운영
- 125 DSL — filter·map·groupBy·join·...
- 126 Processor API — low-level
- 127 Stateful + Interactive Queries — state store·windowing·외부 query
- 128 Testing — TopologyTestDriver·integration
- 129 운영 — security·manage topics·app reset tool
이 시리즈가 끝나면 Kafka Streams 의 거의 모든 영역을 다룬 셈이에요.
한계·실무 함정
1. Kafka 외 source/sink
Kafka Streams 는 Kafka in·Kafka out 이 전제예요. DB·HTTP API 가 source 라면 Connect 와 결합해야 해요.
2. 대규모 분산
수천 노드 ETL 은 Spark·Flink 영역이고, Kafka Streams 는 수십~수백 instance 정도가 적정선이에요.
3. State 의 disk·메모리 비용
stateful 처리는 RocksDB local + changelog topic 으로 돌아가요. state 가 커지면 그만큼 부담이 늘어요.
4. 학습 곡선
DSL 자체는 단순한데 stateful·windowing·join 으로 들어가면 깊이가 확 커져요.
5. 운영 — 일반 Java 앱이지만 stream 처리 특수성
reprocess·offset reset·state restore 같은 별도 운영 도구가 필요해요 (129편).
시험 직전 한 번 더 — Kafka Streams 입문 함정 압축 노트
- Kafka Streams = client 라이브러리 (별도 cluster X)
- Java/Scala 애플리케이션 안에 포함
- 장점 — Elastic·EOS·No separate cluster·Kafka 통합·microservice 친화
- 단점 — Kafka 외 source/sink X (Connect 와 결합)·매우 큰 분산 어려움
- vs Spark/Flink — Kafka Streams = 라이브러리 / Spark·Flink = 별도 cluster
- 선택 — Kafka 안 데이터 + microservice = Kafka Streams / 대규모 분산 ETL = Spark / 매우 낮은 latency = Flink
- KStream = record stream (이벤트 흐름, append-only)
- KTable = changelog stream (key 별 최신 값)
- Stream-Table Duality = 같은 데이터 두 관점, 변환 가능
- DSL (high-level) = 선언적, 90% 환경 충분
- Processor API (low-level) = 세밀 제어, custom
- Topology = Source → Processor → Sink graph
- Kafka Streams 가 topology 를 task 로 분할 + partition 에 매핑
- Use Cases = 변환·집계·windowing·join·stateful·interactive queries
- 학습 로드맵 9편 = Intro·Quickstart·Core Concepts·Write/Run·DSL·Processor·Stateful/IQ·Testing·운영
- 함정 — Kafka 외 source/sink (Connect 결합)
- 함정 — 대규모 분산 한계 (Spark/Flink)
- 함정 — State disk·메모리 비용
- 함정 — Stateful·windowing·join 학습 곡선
- 함정 — 운영 특수성 (reprocess·offset·state restore)
공식 문서: Kafka Streams Introduction 에서 자세한 사양을 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 116편 — Kafka ACL (Authorization 깊이)
- 117편 — Kafka Connect (Source · Sink · Worker 아키텍처)
- 118편 — Kafka Connect 운영 (REST · Status · Error Handler · DLQ)
- 119편 — Kafka Connect Custom Connector 개발
- 120편 — Kafka Connect Config 종합
다음 글: