카프카 핵심 가이드 14장 - 스트림 처리
14.1 스트림 처리란 무엇인가?
스트림 처리의 정의와 특징
1.
무한히 늘어나는 데이터세트(Unbounded Dataset)
•
스트림 처리의 가장 기본적인 특징은 데이터가 끝없이 계속 늘어난다는 점입니다
•
시간이 흐름에 따라 새로운 레코드가 지속적으로 추가됩니다
•
이는 구글, 아마존 등 많은 기업들이 채택한 정의입니다
•
실제 사례: 신용카드 결제, 주식 거래, 택배 배송, 네트워크 이벤트, 센서 데이터 등
•
이벤트 스트림의 주요 특성
•
아래 특성들은 데이터의 크기나 처리 속도와는 무관합니다
•
데이터 형식도 자유롭습니다 (JSON, XML, Avro, Protobuf 등)
•
초당 처리되는 이벤트 수와 관계없이 동일한 원칙이 적용됩니다
◦
순서가 있음 (순서가 있는 이벤트 스트림)
▪
각 이벤트는 다른 이벤트보다 앞서거나 뒤에 발생했다는 시간적 의미를 가집니다
▪
이는 데이터베이스 테이블과의 주요 차이점입니다
▪
실제 예시: 은행 계좌의 입출금 순서
•
입금 후 출금 vs 출금 후 입금은 전혀 다른 결과(초과인출 수수료 등)를 초래할 수 있습니다
•
순서가 중요한 비즈니스 로직을 처리할 수 있습니다
◦
데이터 레코드는 불변함 (불변성(Immutable))
▪
한번 발생한 이벤트는 절대 수정할 수 없습니다
▪
변경이 필요한 경우 새로운 이벤트를 추가합니다
▪
예시:
•
거래 취소: 취소 이벤트를 새로 추가
•
상품 반품: 반품 이벤트를 새로 추가
▪
데이터베이스의 WAL, redo log와 유사한 개념입니다
◦
재생 가능함 (Replayable)
▪
과거의 이벤트 스트림을 그대로 재생할 수 있습니다
▪
중요한 활용 사례:
•
에러 수정
•
새로운 분석 방법 적용
•
감사 수행
▪
카프카가 비즈니스 환경에서 스트림 처리를 확산시킨 주요 이유 중 하나입니다
처리 방식의 구분
1.
요청-응답(Request-Response) 처리
•
처리 시간 특징:
◦
1밀리초 미만 ~ 몇 밀리초 수준의 매우 낮은 지연시간
◦
일정한 응답 시간 보장 필요
•
처리 방식:
◦
블로킹(blocking) 방식으로 동작
◦
요청을 보낸 후 응답이 올 때까지 대기
•
주요 사용 사례:
◦
OLTP(Online Transaction Processing)
◦
POS(Point-of-sale) 시스템
◦
신용카드 결제 시스템
◦
시간 추적 시스템
2.
배치(Batch) 처리
•
처리 시간 특징:
◦
높은 지연시간(몇 분~몇 시간)
◦
대량의 데이터를 한번에 처리(높은 처리량)
•
처리 방식:
◦
사전 설정된 시간(예: 매일 새벽 2시)에 실행
◦
모든 입력 데이터를 한번에 읽고 처리
◦
처리 완료 후 다음 실행 시간까지 대기
•
주요 사용 사례:
◦
데이터 웨어하우스
◦
비즈니스 인텔리전스 시스템
•
장단점:
◦
장점: 높은 효율성과 규모의 경제 달성
◦
단점: 실시간 의사결정에 부적합
3.
스트림(Stream) 처리
•
처리 시간 특징:
◦
요청-응답과 배치 처리의 중간 수준
◦
실시간에 가까운 처리 가능
•
처리 방식:
◦
연속적이고 논블로킹(non-blocking) 방식
◦
데이터를 지속적으로 처리
◦
끊임없이 발생하는 이벤트를 실시간으로 처리
•
주요 사용 사례:
◦
의심스러운 신용카드 거래 탐지, 실시간 가격 조정, 물품 배송 추적, 네트워크 사용 내역 모니터링
스트림 처리 개념
1.
주요 개념들
•
토폴로지 (Topology)
◦
스트림 처리 애플리케이션의 기본 구조
▪
구성 요소
•
소스 스트림(Source Stream): 데이터의 시작점
•
스트림 프로세서(Stream Processor): 데이터 변환 처리 단계
•
싱크 스트림(Sink Stream): 처리된 데이터의 최종 목적지
◦
주요 스트림 프로세서 예시: filter, count, group by, left join
◦
화살표로 연결된 노드 형태로 시각화 가능
•
시간(Time)
◦
이벤트 시간(Event Time):
▪
실제 이벤트 발생 시점
▪
가장 중요한 시간 개념
▪
예: 상품 판매 시각, 웹페이지 조회 시각
◦
로그 추가 시간(Log Append Time):
▪
카프카 브로커에 저장된 시점
▪
이벤트 시간의 근사값으로 활용 가능
▪
일관성 있는 시간 기준으로 사용
◦
처리 시간(Processing Time):
▪
스트림 처리 애플리케이션이 이벤트를 처리하는 시점
▪
신뢰성이 낮아 가능한 사용 지양
▪
같은 이벤트도 처리 시점에 따라 다른 타임스탬프 가질 수 있음
•
상태(State)
◦
로컬/내부 상태
▪
애플리케이션 인스턴스 내부에서만 사용
▪
인메모리 데이터베이스 활용
▪
장점: 매우 빠른 처리 속도
▪
단점: 메모리 크기 제한
◦
외부 상태
▪
외부 데이터베이스에 저장
▪
예: NoSQL 시스템
▪
장점: 크기 제한 없음, 여러 인스턴스 접근 가능
▪
단점: 지연 증가, 복잡도 증가, 가용성 문제
•
스트림-테이블 이원성(Stream-Table Duality)
◦
스트림 특징:
▪
변경 내역을 순차적으로 저장
▪
이벤트의 연속성 보장
◦
테이블 특징:
▪
현재 상태만 저장
▪
변경 가능(mutable)한 레코드
◦
상호 변환:
▪
테이블→스트림: 변경 내역(CDC) 캡처
▪
스트림→테이블: 모든 변경사항 적용(구체화)
•
시간 윈도우(Time Window)
◦
데이터를 시간 단위로 그룹화하여 처리
◦
주요 윈도우 유형:
▪
텀블링 윈도우: 겹치지 않는 고정 크기 윈도우
▪
호핑 윈도우: 겹치는 윈도우
▪
세션 윈도우: 비활동 기간으로 구분되는 윈도우
•
처리 보장(Processing Guarantees)
◦
장애 발생 시에도 각 레코드를 정확히 한 번만 처리
◦
정확한 결과가 필요한 상황에서 필수적인 기능
◦
카프카의 지원
▪
트랜잭션적이고 멱등적인 프로듀서 기능 제공
▪
"정확히 한 번" 의미 구조 지원
◦
카프카 스트림즈에서의 구현
▪
카프카의 트랜잭션 기능을 활용
▪
processing.guarantee 설정을 통한 기능 활성화
참고 (버젼별 구현)
스트림 처리의 주요 디자인 패턴
단일 이벤트 처리
1.
기본 개념
•
각각의 이벤트를 다른 이벤트와 독립적으로 처리하는 가장 단순한 스트림 처리 패턴
•
이벤트가 들어오면 즉시 처리하고 결과를 출력하는 방식
•
상태 저장이나 다른 이벤트와의 관계를 고려할 필요가 없음
2.
맵/필터 패턴의 주요 기능
•
맵(Map) 연산:
◦
입력 이벤트를 다른 형태로 변환
◦
예: JSON을 AVRO 형식으로 변환
◦
예: 이벤트 데이터 정제 또는 보강
•
필터(Filter) 연산:
◦
특정 조건에 맞는 이벤트만 선택
◦
예: ERROR 로그만 선별
◦
예: 특정 임계값 이상의 트랜잭션 필터링
3.
구현 특징
•
간단한 구조 : 입력 → 처리(변환/필터링) → 출력
•
최소한의 컴포넌트만 필요
◦
카프카 프로듀서
◦
카프카 컨슈머
◦
처리 로직
로컬 상태를 사용한 처리
•
주로 윈도우 집계 등 정보 집계에 사용
◦
예시: 주식의 일별 최저가/최고가 계산, 이동평균 계산
◦
상태 저장 필요: 최소값, 총합, 레코드 수 등
1.
로컬 상태의 특징
•
그룹별 집계 작업에 적합
•
데이터를 파티션별로 분류
◦
카프카 파티셔너로 동일 주식 이벤트를 같은 파티션에 저장
◦
각 애플리케이션 인스턴스는 할당된 파티션만 처리
2.
주요 고려사항
A. 메모리 관리
•
인스턴스의 가용 메모리 내에서 관리 필요
•
디스크 저장(spilling) 가능하나 성능 저하 발생
B. 상태 영속성
•
RocksDB 사용: 인메모리 저장 + 디스크 영속성
•
모든 상태 변경을 카프카 토픽에도 저장
•
장애 발생 시 카프카 토픽에서 복구 가능
•
로그 압착으로 토픽 크기 관리
C. 리밸런싱 처리
•
파티션 재할당 시 상태 이전 필요
•
마지막 상태 저장 후 새 인스턴스에서 복구
3.
구현 시 고려사항
•
프레임워크별 로컬 상태 관리 기능 차이
•
사용 프레임워크의 상태 관리 기능 확인 필요
•
빠르게 변화하는 프레임워크 특성 고려
다단계 처리/리파티셔닝
•
전체 데이터를 대상으로 하는 집계나 분석이 필요할 때 사용
•
단일 인스턴스로는 처리할 수 없는 경우 활용
•
여러 단계로 나누어 처리함으로써 복잡한 연산 수행 가능
1.
처리 과정 예시 (상위 10개 주식 선정)
•
1단계: 분산 처리
◦
각 인스턴스에서 개별 주식의 상승/하락 계산
◦
결과를 단일 파티션 토픽에 저장
•
2단계: 통합 처리
◦
하나의 인스턴스에서 전체 결과 통합
◦
최종 상위 10개 주식 선정
외부 검색을 사용한 처리(스트림-테이블 조인)
1.
개요
•
스트림 데이터와 외부 DB 데이터를 결합하는 처리
•
이벤트 보강을 위해 외부 데이터 참조가 필요한 경우 사용
•
예: 클릭 이벤트에 사용자 프로필 정보 추가
2.
구현 방식
A. 직접 DB 조회
•
장점: 실시간 데이터 확인 가능
•
단점: 높은 지연시간, DB 과부하, 의존성 문제
B. 로컬 캐시
•
장점: 빠른 접근, DB 부하 감소
•
과제: 캐시 일관성, 갱신 전략, 메모리 관리
C. CDC 활용
•
DB 변경사항을 스트림으로 캡처하여 로컬 캐시 갱신
•
장점: 낮은 DB 부하, 높은 성능, 안정적 동기화
3.
최적 구현
•
CDC와 로컬 캐시 조합이 가장 효과적
•
변경 이벤트 스트림으로 캐시 최신성 유지
•
로컬 상태 저장소로 성능 확보
스트림-테이블 조인
1.
기본 개념
•
이벤트 스트림의 각 레코드를 테이블의 현재 상태와 조인
•
테이블은 데이터베이스 테이블의 변경 사항을 캡처한 스트림으로부터 생성됨
•
CDC(Change Data Capture)를 통해 데이터베이스 변경사항을 스트림으로 캡처
2.
로컬 상태 저장소 활용
•
테이블 데이터를 스트림 처리 애플리케이션의 로컬에 캐시
•
외부 데이터베이스 조회 없이 빠른 조인 수행 가능
•
메모리나 로컬 디스크에 상태 저장
3.
자동 업데이트 메커니즘
•
테이블 데이터가 변경되면 변경 이벤트가 스트림으로 전달
•
변경 이벤트를 기반으로 로컬 상태 저장소 자동 업데이트
•
항상 최신 데이터로 조인 수행 가능
4.
장점
•
외부 조회 대비 지연 시간 감소
•
데이터베이스 부하 감소
•
높은 처리량 달성
•
장애 발생 시 자동 복구 가능
테이블-테이블 조인
•
두 개의 구체화된 테이블 간 조인
•
윈도우 처리 없이 현재 상태 기준으로 조인
•
변경 이벤트 스트림으로부터 구체화된 테이블 생성
•
지원되는 조인 유형
◦
동등 조인(equi-join)
▪
동일한 키를 가진 테이블 간 조인
▪
동일한 파티션 방식 필요
▪
여러 인스턴스에 효율적으로 분산 가능
◦
외래 키 조인(foreign key join)
▪
한 테이블의 키와 다른 테이블의 임의 필드 간 조인
▪
더 유연한 조인 조건 지원
스트리밍 조인
•
두 개의 실제 이벤트 스트림 간의 조인
•
무한(unbounded) 특성을 가진 스트림들을 시간 윈도우 기준으로 조인
◦
스트리밍 조인을 윈도우 조인 이라고도 부르는 이유
•
과거와 현재의 이벤트 전체를 대상으로 조인
1.
작동 방식
•
특정 시간 윈도우 내에서 발생한 이벤트들끼리 조인
•
동일한 키값을 가진 이벤트들을 매칭
•
RocksDB를 사용하여 조인 윈도우 상태 저장
2.
구현 요구사항
•
두 스트림이 동일한 조인 키로 파티셔닝되어야 함
•
같은 키를 가진 이벤트들이 같은 파티션에 저장되도록 설계
•
동일 파티션의 이벤트들은 같은 태스크에서 처리
3.
활용 예시
•
검색 쿼리 스트림과 클릭 이벤트 스트림 조인
•
검색 후 특정 시간 내의 클릭 이벤트만 매칭
•
사용자 행동 분석이나 인기 검색결과 분석에 활용
비순차 이벤트 처리 (Out-of-sequence Events)
1.
문제 상황
•
WiFi 단절, 네트워크 장애, 불안정한 연결 등으로 이벤트가 순서대로 도착하지 않음
•
특히 IoT, 제조업 환경에서 자주 발생
•
뒤늦게 과거 이벤트들이 한꺼번에 도착하는 상황 발생
2.
필수 처리 요구사항
•
순서 이탈 감지: 이벤트 시간과 현재 시각 비교
•
복구 시간 범위 정의: 얼마나 오래된 이벤트까지 처리할지 결정
•
이벤트 재정렬: 늦게 도착한 과거 이벤트들을 올바른 순서로 정렬
•
결과 갱신 기능: 늦게 도착한 이벤트로 인한 결과 수정 가능
3.
프레임워크 지원 기능
•
처리 시간과 독립된 이벤트 시간 개념 지원
•
변경 가능한 집계 윈도우 유지
•
윈도우 유지 기간 설정 가능
•
로컬 상태에 다수의 윈도우 저장
4.
카프카 스트림즈의 구현
•
집계 결과를 로그 압축된 토픽에 저장
•
키별로 최신 값만 유지
•
늦은 이벤트로 인한 결과 변경 시 새 결과값으로 자동 대체
재처리하기
1.
목적 : 애플리케이션 업그레이드나 버그 수정 시 이벤트 스트림을 안전하게 재처리
2.
핵심 방식
•
신/구 버전을 별도 컨슈머 그룹으로 동시 운영
•
신버전은 처음부터 모든 이벤트 재처리
•
결과 비교 후 점진적 전환
3.
이점
•
안전한 버전 전환
•
결과 검증 가능
•
데이터 손실 방지
•
롤백 용이
인터랙티브 쿼리
1.
개념
•
스트림 처리 애플리케이션의 상태를 직접 조회하는 기능
•
분산된 애플리케이션 인스턴스들의 상태에 접근 가능
2.
사용 목적
•
상태 저장소에서 직접 데이터 읽기
•
테이블 형태의 처리 결과를 빠르게 조회
•
결과 토픽을 통하지 않고 즉각적인 결과 확인
3.
장점
•
더 빠른 결과 조회
•
간단한 접근 방식
•
실시간 상태 확인 가능
4.
활용 사례
•
실시간 순위표 조회 (예: 베스트셀러 10종)
•
현재 집계 상태 확인
•
테이블 형태의 결과 조회
예제로 보는 카프카 스트림즈
1.
카프카 스트림즈 API 특징
•
두 가지 API 제공: 저수준 Processor API, 고수준 스트림즈 DSL
•
사용이 간단하고 카프카와 함께 배포됨
•
DSL을 통해 연속적인 변환 정의 가능
2.
애플리케이션 구현 단계
•
StreamsBuilder로 처리 토폴로지 생성
•
토폴로지는 이벤트 변환을 정의하는 DAG(유향 비순환 그래프)
•
KafkaStreams 객체 생성 및 실행
3.
기본 설정 요소
•
애플리케이션 ID (인스턴스 협력 및 저장소 식별용)
•
부트스트랩 서버 설정
•
Serde 클래스 지정 (직렬화/역직렬화용)
단어 개수 세기 예제
•
입력 스트림 생성
•
단어 분할 및 변환
•
필터링
•
그룹화 및 집계
•
결과 출력
// 카프카 스트림즈를 설정
// APPLICATION_ID_CONFIG: 스트림 애플리케이션의 고유 식별자
// BOOTSTRAP_SERVERS_CONFIG: 카프카 클러스터 연결 주소
// DEFAULT_KEY_SERDE_CLASS_CONFIG: 키의 Serde(Serializer/Deserializer) 클래스
// DEFAULT_VALUE_SERDE_CLASS_CONFIG: 값의 Serde 클래스
public class WordCountExample {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
// 애플리케이션 ID 설정
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "wordcount");
// 카프카 브로커 주소 설정
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
// 키의 직렬화/역직렬화 클래스 설정
props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG,
Serdes.String().getClass().getName());
// 값의 직렬화/역직렬화 클래스 설정
props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG,
Serdes.String().getClass().getName());
}
}
// 스트림즈 토폴로지를 생성
// 1. 스트림 빌더 및 소스 스트림 생성
StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> source = builder.stream("wordcount-input");
// 2. 단어 분리 패턴 정의
final Pattern pattern = Pattern.compile("\\W+");
// 3. 스트림 처리 파이프라인 구성
KStream<String, String> counts = source
// 문자열을 소문자로 변환하고 단어로 분리
.flatMapValues(value -> Arrays.asList(pattern.split(value.toLowerCase())))
// 각 단어를 키로 설정
.map((key, value) -> new KeyValue<String, String>(value, value))
// "the" 단어 필터링
.filter((key, value) -> (!value.equals("the")))
// 키별로 그룹화
.groupByKey()
// 개수 세기
.count()
// Long을 String으로 변환
.mapValues(value -> Long.toString(value))
// KTable을 KStream으로 변환
.toStream();
// 4. 결과를 출력 토픽에 저장
counts.to("wordcount-output");
// 애플리케이션이 수행할 변환의 흐름을 정의했으므로, 실행
// 5. 스트림 처리 실행
KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();
// 예제를 위한 임시 실행(5초)
Thread.sleep(5000L);
streams.close();
Java
복사
•
장점
◦
간단한 클러스터 구성 가능
◦
별도 클러스터 관리 시스템 불필요
◦
개발/운영 환경 동일하게 실행 가능
주식 시장 통계 예제
1.
예제 개요
•
주식 거래 이벤트 스트림 처리
•
종목코드, 매도 호가, 매도량 데이터 처리
•
5초 단위 윈도우로 통계 계산
•
매초 갱신되는 결과 생성
2.
주요 통계값
•
5초 윈도우별 최저 매도가
•
5초 윈도우별 거래량
•
5초 윈도우별 평균 매도가
3.
구현 특징
•
Gson 라이브러리 사용한 커스텀 Serde 구현
•
Trade 객체 사용 (종목 코드, 매도 호가, 매도량 포함)
•
윈도우 처리와 집계 연산 결합
4.
처리 단계 및 전체 코드
•
기본 설정: 애플리케이션 ID, 브로커, Serde 설정
•
커스텀 Serde: Trade 객체 직렬화/역직렬화
•
스트림 처리: 윈도우 처리, 집계, 평균 계산
•
결과 출력: 윈도우 적용된 데이터 저장
// 1. 기본 설정
Properties props = new Properties();
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "stockstat");
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, Constants.BROKER);
props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG,
Serdes.String().getClass().getName());
props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG,
TradeSerde.class.getName());
// 2. 커스텀 Serde 클래스 정의
static public final class TradeSerde extends WrapperSerde<Trade> {
public TradeSerde() {
super(new JsonSerializer<Trade>(),
new JsonDeserializer<Trade>(Trade.class));
}
}
// 3. 스트림 처리 로직
KStream<Windowed<String>, TradeStats> stats = source
// 키 기준 그룹화
.groupByKey()
// 5초 윈도우, 1초마다 진행
.windowedBy(TimeWindows.of(Duration.ofMillis(windowSize))
.advanceBy(Duration.ofSeconds(1)))
// 집계 연산
.aggregate(
() -> new TradeStats(),
(k, v, tradestats) -> tradestats.add(v),
Materialized
.<String>as("trade-aggregates")
.withValueSerde(new TradeStatsSerde())
)
// 스트림으로 변환
.toStream()
// 평균 가격 계산
.mapValues(trade -> trade.computeAvgPrice());
// 4. 결과를 출력 토픽에 저장
stats.to("stockstats-output",
Produced.keySerde(
WindowedSerdes.timeWindowedSerdeFrom(String.class, windowSize)));
Java
복사
5.
주요 특징
•
자동 장애 복구 가능
•
확장 가능한 구조
•
로컬 상태 관리 자동화
•
최소한의 설정으로 복잡한 처리 구현
클릭 스트림 확장 예제
1.
예제 개요
•
웹사이트 클릭 스트림 데이터 처리
•
세 가지 데이터 소스 조인:
◦
클릭 스트림
◦
사용자 프로필 데이터베이스
◦
웹 검색 스트림
2.
구현 코드
// 소스 스트림 생성
KStream<Integer, PageView> views = builder.stream(
Constants.PAGE_VIEW_TOPIC,
Consumed.with(Serdes.Integer(), new PageViewSerde()));
KStream<Integer, Search> searches = builder.stream(
Constants.SEARCH_TOPIC,
Consumed.with(Serdes.Integer(), new SearchSerde()));
KTable<Integer, UserProfile> profiles = builder.table(
Constants.USER_PROFILE_TOPIC,
Consumed.with(Serdes.Integer(), new ProfileSerde()));
// 스트림-테이블 조인
KStream<Integer, UserActivity> viewsWithProfile =
views.leftJoin(profiles, (page, profile) -> {
// 사용자 프로필 정보와 페이지 뷰 결합
});
// 스트림-스트림 조인
KStream<Integer, UserActivity> userActivityStream =
viewsWithProfile.leftJoin(searches,
// 검색 정보 결합
// 1초 윈도우 적용
JoinWindows.of(Duration.ofSeconds(1))
.before(Duration.ofSeconds(0)));
Java
복사
3.
주요 조인 패턴
•
스트림-테이블 조인
◦
클릭 스트림과 사용자 프로필 결합
◦
정적 데이터로 스트림 확장
•
스트림-스트림 조인
◦
확장된 클릭 데이터와 검색 데이터 결합
◦
시간 윈도우 기반 조인
4.
활용
•
사용자 행동 분석
•
검색 패턴 파악
•
개인화된 상품 추천
•
타겟 광고 집행
카프카 스트림즈: 아키텍처 개요
1.
토폴로지 생성과 실행
•
모든 스트림즈 애플리케이션은 하나의 토폴로지(DAG) 구현
•
토폴로지는 이벤트의 입력부터 출력까지의 모든 처리 단계를 포함
•
실행 단계:
◦
논리적 토폴로지 정의 (KStream, KTable 객체 생성)
◦
물리적 토폴로지 생성 (StreamsBuilder.build())
◦
토폴로지 실행 (KafkaStreams.start())
2.
토폴로지 최적화
•
카프카 스트림즈는 DSL 메서드의 독립적 변환으로 인해 전체적으로 최적화 되지 않은 상태 ⇒ 최적화 필요
•
스트림즈 어플리케이션 실행 단계 요약
1.
논리적 토폴로지 정의
•
KStream, KTable 객체 생성
•
DSL 작업(필터, 조인 등) 정의
2.
물리적 토폴로지 생성
•
StreamsBuilder.build() 메서드 사용
•
논리적 토폴로지를 실행 가능한 형태로 변환
3.
토폴로지 실행
•
KafkaStreams.start() 호출
•
실제 데이터 처리(읽기, 처리, 쓰기) 수행
•
StreamsConfig.TOPOLOGY_OPTIMIZATION 설정으로 최적화 활성화
◦
이 설정 없이 build 메서드 호출 ⇒ 최적화 적용 x
•
실행 시간과 데이터량 비교를 통한 최적화 효과 검증
3.
토폴로지 테스트
•
TopologyTestDriver를 사용한 단위 테스트
•
EmbeddedKafkaCluster나 Testcontainers를 통한 통합 테스트
•
도커 기반 격리된 테스트 환경 권장
4.
토폴로지 규모 확장
a.
기본 확장 구조
•
다수의 스레드를 통한 병렬 처리
•
애플리케이션 인스턴스 간 부하 분산
•
단일/다중 서버 환경 모두 지원
•
균등한 작업 분배
b.
태스크 기반 처리
•
토픽 파티션 수에 따른 태스크 분할
•
각 태스크는 특정 파티션 담당
•
독립적인 이벤트 처리 및 상태 관리
•
병렬 처리의 기본 단위로 동작
c.
조인 작업 처리
•
관련 파티션들을 동일 태스크에 할당
•
동일한 조인 키와 파티션 수 요구
•
독립적인 조인 연산 수행
d.
리파티셔닝 처리
•
새로운 키/파티션으로 데이터 재구성
•
서브 토폴로지로 분할 처리
•
독립적인 병렬 실행 유지
•
중간 토픽을 통한 데이터 전달
5.
장애 처리
•
커밋된 오프셋 기반의 처리 재개
•
로컬 상태 저장소 복구 기능
•
태스크 고가용성을 위한 컨슈머 코디네이션 기능 사용
•
스탠바이 레플리카를 통한 빠른 장애 복구
•
압착 설정을 통한 복구 시간 최적화
프레임워크 선택 시 고려사항
1.
애플리케이션 유형별 고려사항
•
데이터 수집: 단순 수집용 vs 스트림 처리 시스템
•
밀리초 단위 작업: 요청-응답 패턴 vs 저지연 스트림 처리
•
비동기 마이크로서비스: 메시지 버스 통합성, 로컬 상태 관리
•
준실시간 데이터 분석: 복잡한 집계/조인 연산 지원
2.
시스템 선택 기준
•
시스템 운용성
◦
배포 용이성
◦
모니터링/트러블슈팅
◦
확장성
◦
인프라 통합성
◦
재처리 용이성
•
개발 효율성
◦
사용 및 디버깅 용이성
◦
개발/배포 시간
◦
API 품질과 추상화 수준
3.
커뮤니티 중요성
•
지속적인 기능 개선
•
품질 보증
•
신속한 버그 수정
•
문제 해결 지원
•
풍부한 참고 자료