Kafka Streams는 Kafka 토픽을 입력으로 받아 애플리케이션 내부에서 스트림 처리(변환/집계/조인)를 수행하고, 결과를 다시 Kafka 토픽으로 내보내는 JVM 라이브러리입니다. “별도 스트림 처리 클러스터 없이(예: Flink 클러스터 운영 없이) 서비스처럼 배포/스케일링”하는 접근이 핵심입니다. Source
핀테크 도메인은 결제 승인/거절, 정산, 한도, 이상거래 탐지(FDS), 알림처럼 “이벤트가 계속 흐르고” “즉시 반응”이 중요한 영역이 많습니다. Kafka Streams는 이를 토픽 → 처리 → 토픽 형태로 표준화하기 좋습니다. Source
핀테크의 핵심 로직(예: “10분 내 동일 사용자 5회 결제”, “가맹점별 승인율”, “사용자별 한도 소진”)은 대부분 누적 상태/윈도우가 필요합니다. Kafka Streams는 로컬 state store를 이용해 윈도우 조인/집계 같은 stateful 연산을 빠르게 지원합니다. Source
Kafka Streams는 장애가 나도 “레코드가 한 번만 처리된 것과 같은 효과”를 보장하는 exactly-once processing semantics를 지원합니다. 핀테크에서 중복 승인/중복 정산은 치명적이므로 이 축이 매우 중요합니다. Source
Kafka Streams DSL은 KStream/KTable 등의 추상화를 제공합니다. Source
토폴로지는 필터/변환/조인/집계를 연결한 처리 그래프입니다.
아래 예시는 “이런 요구사항이면 Kafka Streams가 깔끔해진다”를 기준으로 정리했습니다.
상황: 결제 승인 이벤트에서 카드사별 필드가 제각각 → 내부 표준 포맷으로 정규화하고, 국가/통화/채널에 따라 토픽을 분기.
mapValues, filter, branch, selectKeypayments.approved.normalized, payments.declined.normalized 같은 토픽으로 재발행DSL 개념은 공식 DSL 문서 기반으로 이해할 수 있습니다. Source
상황: 동일 사용자/동일 카드로 N분 내 결제 시도 횟수가 임계치를 넘으면 경보 생성
userId 또는 cardHashfraud.alertsKafka Streams는 윈도우 집계 같은 stateful 연산을 지원한다고 core concepts에서 강조합니다. Source
상황: 거래가 들어오는 순간, 사용자 위험등급/한도 상태(최신)를 붙여서 승인정책을 적용해야 함.
payments.tx (KStream)risk.user-score (KTable; 최신 위험등급)payments.enriched → 이후 룰 엔진/머신러닝/심사로 전달KStream/KTable은 DSL에서 공식적으로 정의된 추상화입니다. Source
상황: 스트림 처리 결과가 “정산/원장계”에 영향을 줌. 중복 이벤트는 곧 금액 오류.
Kafka Streams가 exactly-once processing semantics를 지원한다는 점은 core concepts에 명시되어 있습니다. Source
상황: “현재 사용자의 실시간 한도 소진액/위험 플래그”를 API로 바로 제공하고 싶음.
Kafka Streams는 state store를 직접 읽어 조회할 수 있는 Interactive Queries를 제공합니다. Source
아래는 “결제 이벤트 → 사용자별 5분 내 시도 횟수 집계 → 경보 토픽”의 전형적인 흐름입니다(설계 감 잡기용).
StreamsBuilder builder = new StreamsBuilder();
KStream<String, PaymentEvent> payments =
builder.stream("payments.tx", Consumed.with(Serdes.String(), paymentSerde));
// userId를 key로 설정
KStream<String, PaymentEvent> keyed =
payments.selectKey((k, v) -> v.userId());
// 5분 윈도우 집계(개념 스케치)
KTable<Windowed<String>, Long> attempts =
keyed.groupByKey()
.windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))
.count();
// 임계치 넘으면 alerts 토픽으로
attempts.toStream()
.filter((windowedUserId, count) -> count >= 5)
.mapValues((windowedUserId, count) ->
new FraudAlert(windowedUserId.key(), count, windowedUserId.window().startTime()))
.to("fraud.alerts", Produced.with(windowedStringSerde, fraudAlertSerde));
윈도우 집계/상태 저장 자체가 Kafka Streams의 핵심 capability라는 점은 core concepts에서 확인할 수 있습니다. Source
Kafka Streams는 stateful 처리에서 로컬 상태 저장을 쓰는 경우가 많고, RocksDB가 흔히 사용됩니다. 성능/메모리/디스크 튜닝 이슈가 실무 포인트가 됩니다.
Kafka 내부(토픽 간)에서는 EOS가 강력하지만, 외부 시스템(DB/외부 API)까지 포함하면 별도 멱등성/트랜잭션 아키텍처가 필요할 수 있습니다. “Kafka exactly-once가 실제로 무엇을 의미하나?”는 그림으로 이해하면 훨씬 빠릅니다.
Confluent의 Kafka Streams 예제 레포(다양한 데모/패턴 모음):
https://github.com/confluentinc/kafka-streams-examples
Source
Interactive Queries(공식 문서):
https://docs.confluent.io/platform/current/streams/developer-guide/interactive-queries.html
Source