매 transaction 이 즉시 처리되어 실시간 분석. 사용자 행동 → 5초 후 대시보드. 이게 streaming. batch 의 hourly / nightly 와 다른 세계. Kafka / Kinesis / Flink — 이 가이드는 streaming 의 핵심 개념 (windowing, watermark, exactly-once) 을 정리한다.
Batch vs Streaming
Batch:
- 큰 chunk 데이터를 한꺼번에 처리
- "오늘 자정의 매출 합산" 매일 1회
- 도구: cron + Spark / Hive / dbt
Streaming:
- 매 record 가 도착하면 즉시 처리
- "지난 5분의 활성 user 수" 매 초 갱신
- 도구: Kafka / Kinesis (transport) + Flink / Kafka Streams / Spark Streaming (compute)
Trade-off:
- Batch: 단순, 정확한 결과, 큰 dataset 효율
- Streaming: 빠른 응답, 운영 복잡, watermark / late event 문제
→ 두 가지 다 필요 (Lambda Architecture). modern 은 Kappa (streaming
만으로 둘 다 처리) 로 단순화 추세.Streaming 의 핵심 component
Transport (메시지 broker):
- Kafka — partition + consumer group + persistent log
- Kinesis (AWS) — Kafka 의 managed 변형
- Google Pub/Sub — push 모델
- RabbitMQ — queue 중심 (AMQP)
- Pulsar — multi-tenant, geo-replication
Compute (stream processing):
- Kafka Streams — Java/Scala 라이브러리, Kafka 내장
- Flink — 가장 powerful, exactly-once, low-latency
- Spark Streaming — Spark 의 micro-batch
- Beam — 추상 layer (Flink / Dataflow / Spark 위)
Sink (저장 / external):
- Warehouse (BigQuery, Snowflake)
- OLAP store (ClickHouse, Druid)
- 다른 Kafka topic (chain)
- DB (CDC 의 역방향)Windowing — 시간 단위 grouping
stream 의 "지난 5분 합계" 같은 query 가 어떻게?
3 windowing 패턴:
1. Tumbling (고정 크기, 겹침 없음)
|---1min---|---1min---|---1min---|
각 window 가 1 분, 겹침 0.
"매 분의 요청 수" — 단순.
2. Sliding (겹침 있음)
|--5min--|
|--5min--|
|--5min--|
slide=1min, window=5min → 매 분 갱신, 지난 5분 평균.
3. Session (사용자 활동 기반)
user 의 마지막 event 후 30 초 idle 면 session 종료.
user 별 동적 window 크기.
선택:
- Tumbling: 단순 metric (per-minute counter)
- Sliding: smooth metric (rolling avg)
- Session: user behavior (web session, game session)Watermark — Late Event 처리
문제: event 가 late 도착하면?
09:00:00 — A
09:00:01 — B
09:00:02 — C
09:00:30 — Z (실은 09:00:01 의 event, network 지연)
"09:00:00 ~ 09:00:10 window" 의 합계 계산:
- 09:00:10 시점에 close? Z 가 빠짐
- 무한 wait? close 불가
Watermark 의 해결:
- "현재 시점에 이 시간 이전의 모든 event 는 도착했다고 가정"
- watermark = max(event_time) - allowedLateness
- watermark 가 window 끝을 넘으면 → window close + emit
예: allowedLateness = 30s
09:00:10 의 watermark = max(09:00:02) - 30s = 08:59:32
→ window 09:00:00 ~ 09:00:10 아직 close 안 함 (watermark < 09:00:10)
09:00:40 의 watermark = 09:00:10
→ window close, Z 도 포함
Late event 처리:
- discard (default)
- side output (별도 sink, late report)
- accumulate + retract (이전 결과 정정)Exactly-Once Semantics — 왜 어려운가
distributed system 에서 "정확히 한 번" 처리 = 가장 어려운 문제.
가능한 보장:
- at-most-once: 보내고 잊기. event 손실 가능.
- at-least-once: ack 까지 retry. 중복 가능.
- exactly-once: 손실 X + 중복 X.
문제: producer / broker / consumer / sink 4 layer 의 모든 fail 점을 cover.
Kafka 의 exactly-once (Kafka 0.11+):
- Idempotent producer (producer ID + sequence number)
- Transactional API (multiple partition write atomic)
- Consumer 가 transaction commit log 기반 read
Flink 의 exactly-once:
- Checkpoint (분산 snapshot) + state recovery
- 2-phase commit sink (Kafka, file system, JDBC)
함정:
- side effect (외부 API 호출) 의 exactly-once 는 보장 어려움
→ idempotent API 또는 dedup key 사용
- exactly-once 의 throughput 대가 — 매 batch 에 transaction overheadStream-Table Duality
Kafka Streams / Flink 의 핵심 통찰:
Stream = sequence of immutable events
Table = current state (key → value)
서로 변환:
- Stream → Table: aggregate events into state
(예: user_signed_up events → user_table)
- Table → Stream: emit changes as events
(예: user_table UPDATE → user_changed events)
→ 같은 데이터를 두 view 로:
table view = "현재 상태"
stream view = "변경 history"
응용:
- KTable + KStream의 join (last value 와 새 event)
- materialized view (table) + change log (stream)
- event sourcing 의 자연스러운 확장실제 use case
- real-time analytics — 사용자 행동 → 5초 후 대시보드
- fraud detection — 거래 발생 즉시 anomaly 검사
- recommendation — 사용자 click → 다음 추천에 반영
- IoT — sensor 수만 개의 실시간 monitoring
- microservice 간 event-driven — service A 의 이벤트가 B, C, D 의 trigger
- CDC downstream — DB 변경 → 검색 인덱스 / 캐시 자동 update
흔한 함정
- watermark 없이 window — late event 처리 불완전. allowedLateness 명시.
- infinite state — group-by user_id 의 state 가 모든 user 보유 → memory 폭발. TTL 또는 state backend (RocksDB).
- exactly-once 가정 + side effect — sink 가 외부 API 면 보장 깨질 수 있음. idempotent.
- partition skew — 한 user 의 event 가 90% → 한 consumer 만 부하. 더 fine-grained key.
- streaming 으로 batch job 대체 — 단순 nightly aggregate 면 batch 가 더 단순. streaming 은 latency 가 핵심.
마무리
Streaming = batch 의 generalization — record-by-record 처리. windowing 으로 시간 단위 query, watermark 로 late event 처리, exactly-once 의 어려움. Kafka + Flink 가 modern 표준.
실용 — real-time 이 진짜 필요할 때만. nightly batch 로 충분하면 그게 단순. "실시간" 요구가 명확하면 → Kafka (transport) + Kafka Streams (소규모) 또는 Flink (큰 규모) + 결과는 ClickHouse / Druid / OLAP.