Kafka Streams는 실시간 데이터 처리를 위한 강력한 도구로, KStream과 KTable이라는 두 가지 데이터 구조를 제공합니다. 이번 글에서는 이 두 데이터 구조의 개념과 차이를 살펴보고, 실제 KStream-KStream, KStream-KTable, KTable-KTable 조인의 예제를 설명하겠습니다.
KStreams - KStreams 조인
[개념]
KStream-KStream 조인은 두 개의 실시간 데이터 스트림을 결합합니다.
이 조인은 타임 윈도우를 기준으로 이루어지며, 설정된 기간 내에 동일한 키를 가진 데이터를 결합합니다.
[조인의 특징]
- 타임 윈도우가 필수적입니다.
- 데이터가 실시간으로 들어오므로, 시간이 지나면 윈도우가 닫히고 더 이상 데이터를 결합할 수 없습니다.
[사용 사례]
- 두 개의 스트림에서 발생하는 동시에 일어나는 이벤트를 결합
- 예: 결제 이벤트 스트림과 배송 요청 스트림의 결합
[시나리오: 결제와 배송 요청 이벤트 결합]
- payments 스트림: 결제 정보 Key: 주문 ID, Value: 결제 상태
- shipments 스트림: 배송 요청 정보 Key: 주문 ID, Value: 배송 상태
KStream<String, String> payments = builder.stream("payments");
KStream<String, String> shipments = builder.stream("shipments");
// 타임 윈도우를 적용한 조인
KStream<String, String> joinedStream = payments.join(
shipments,
(payment, shipment) -> "Payment: " + payment + ", Shipment: " + shipment,
JoinWindows.of(Duration.ofMinutes(5)) // 5분 윈도우 설정
);
joinedStream.to("joined-orders");
Key: "order123", Value: "Payment: completed, Shipment: dispatched"
KStreams - KTable 조인
[개념]
KStream-KTable 조인은 실시간 스트림(KStream)과 상태 기반 데이터(KTable)를 결합합니다.
KStream의 각 이벤트가 KTable의 현재 상태와 조인됩니다.
[조인의 특징]
- KStream의 데이터는 실시간으로 계속 흐르지만, KTable은 현재 상태만 유지합니다.
- KStream의 각 레코드는 KTable의 최신 상태와 결합됩니다.
[사용 사례]
- 실시간 스트림을 기존 참조 데이터와 결합
- 예: 사용자 행동 스트림과 사용자 프로필 테이블 결합
[시나리오: 사용자 행동 로그와 사용자 프로필 조인]
- user-actions 스트림: 사용자가 수행한 행동 Key: 사용자 ID, Value: 행동 타입 (click, purchase)
- user-profiles 테이블: 사용자 프로필 정보 Key: 사용자 ID, Value: 사용자 이름과 지역
KStream<String, String> userActions = builder.stream("user-actions");
KTable<String, String> userProfiles = builder.table("user-profiles");
KStream<String, String> joinedStream = userActions.leftJoin(
userProfiles,
(action, profile) -> {
if (profile == null) return action + " by unknown user";
return action + " by " + profile;
}
);
joinedStream.to("user-actions-with-profile");
Key: "user123", Value: "click by Alice, US"
Key: "user456", Value: "purchase by unknown user"
KStreams - KTable 조인
[개념]
KTable-KTable 조인은 두 개의 상태 기반 데이터(KTable)를 결합합니다.
이는 KTable의 키를 기준으로 데이터가 업데이트될 때마다 결과 테이블도 업데이트됩니다.
[조인의 특징]
- 조인은 상태 기반으로 동작하며, 입력 데이터가 변경될 때마다 결과 테이블도 갱신됩니다.
- 결합된 데이터는 항상 최신 상태를 유지합니다.
- TTL은 KTable 상태의 만료 시간을 관리합니다.
- TTLEmitter를 사용하여 주어진 TTL 기간이 지난 데이터를 삭제.
- 이를 통해 상태 크기를 제어하고 메모리 사용량을 최적화.
[사용 사례]
- 두 개의 참조 데이터 테이블을 병합하여 확장된 참조 데이터를 생성
- 예: 상품 정보 테이블과 카테고리 정보 테이블 결합
[시나리오: 상품 정보와 카테고리 정보 결합]
- product-info 테이블: 상품의 이름과 가격Key: 상품 ID, Value: 상품 이름과 가격
- category-info 테이블: 상품의 카테고리 정보Key: 상품 ID, Value: 카테고리 이름
KTable<String, String> productInfo = builder.table("product-info");
KTable<String, String> categoryInfo = builder.table("category-info");
KTable<String, String> joinedTable = productInfo.join(
categoryInfo,
(product, category) -> product + " in category: " + category
);
joinedTable.toStream().to("product-with-category");
Key: "product123", Value: "Coffee Machine, $120 in category: Appliances"
조인의 차이점
KStream-KStream | 스트림-스트림 | 타임 윈도우 기반, 실시간 이벤트 간 결합 | 결제와 배송 요청 스트림 결합 |
KStream-KTable | 스트림-테이블 | 실시간 스트림과 상태 기반 데이터 결합 | 사용자 행동 로그와 사용자 프로필 조인 |
KTable-KTable | 테이블-테이블 | 상태 데이터 간 조인, 항상 최신 상태 유지 | 상품 정보와 카테고리 정보 병합 |
실무 사례: KTable - KTable 조인으로 데이터 정확도 개선
실무에서 제가 결합하고자 했던 데이터는 상품 정보 A와 상품 정보 B였습니다. 기존에는 KTable-KStream 조인을 사용했으나, 이 방식에서는 오래된 데이터 A와 최신 데이터 B가 결합되는 문제가 있었습니다. 이는 두 정보가 모두 실시간 데이터가 아니라 상태성 데이터였기 때문에 발생한 이슈였습니다.
이를 해결하기 위해 KTable-KTable 조인으로 변경하고, TTL을 설정하여 KTable 상태의 만료 시간을 관리했습니다. 이로써 과거 데이터가 결합되어 상품 정보에 반영되는 문제를 해결할 수 있었습니다.
결론
Kafka Streams의 조인 연산은 다양한 데이터 소스를 결합하여 강력한 실시간 데이터 파이프라인을 구축할 수 있는 도구입니다
- KStream-KStream: 이벤트 간 시간 관계를 분석하고 처리
- KStream-KTable: 실시간 스트림 데이터를 참조 데이터와 결합
- KTable-KTable: 상태 기반 데이터의 지속적인 동기화 및 최신 상태 유지
Kafka Streams를 활용한 조인 방식은 데이터의 특성과 요구사항에 따라 달라져야 합니다.실시간 스트림인지, 상태 기반 데이터인지 정확히 이해하고 올바른 조인 방식을 선택하는 것이 데이터 파이프라인의 정확성과 효율성을 높이는 핵심입니다.
참고
'Java & Spring Boot' 카테고리의 다른 글
Kafka Streams: 실시간 데이터 처리를 위한 도구 (1) | 2024.11.20 |
---|---|
Java Redis 직렬화 삼총사: Json, String, JDK (1) | 2024.11.10 |
SSE와 WebSocket, 그들은 왜 실시간 통신의 라이벌이 되었을까? (6) | 2024.10.25 |
Spring Boot의 MongoDB 연동: MongoTemplate vs MongoRepository (2) | 2024.10.10 |
자바의 기본 트랜잭션 매니저와 그 구현체들 (0) | 2024.04.13 |