카프카 스트림즈는 토픽에 적재된 데이터를 상태기반(Stateful) 또는 비상태기반(stateless)으로 실시간 변환하여 달느 토픽에 적재하는 라이브러리이다.
다양한 아파치 오픈소스 애플리케이션이 존재하지만 카프카 스트림즈를 사용해야하는 이유는 상당히 많다. 스트림즈는 카프카에서 공식적으로 지원하는 라이브러리이며, 매번 카프카 버전이 오를 때마다 스트림즈 자바 라이브러리도 같이 릴리즈가 되기 때문이다. 이런 이유로 카프카 클러스터와 완벽하게 호환되면서 스트림 처리에 필요한 편리한 기능들을 제공한다. 또한 장애가 발생하더라도 한번 할 수 있도록 장애 허용 시스템을 지원하기 때문에 데이터 처리 안전성이 뛰어나다.
스트림 프로세싱에 쓰일 만한 다양한 기능들을 자체 API로 만들어 놓았다. 그렇기 때문에 대부분의 변환 로직을 어렵지 않게 개발할 수 있다.
스트림즈 DSL의 3가지 개념
위의 3가지 개념은 컨슈머, 프로듀서, 프로세스 API에서 사용되지 않고 스트림즈 DSL에서만 사용되는 개념이다.
레코드의 흐름을 표현한 것으로 메시지 키와 메시지 값으로 구성되어 있다. KStream으로 데이터를 조회하면 토픽에 존재하는 모든 레코드가 출력된다. 컨슈머로 토픽을 구독하는 것과 동일 선상에서 사용하는 것이라고 볼 수 있다.
메시지 키를 기준으로 묶어서 사용한다. KStream은 토픽의 모든 레코드를 조회할 수 있지만 KTable은 유니크한 메시지 키를 기준으로 가장 최신 레코드를 사용한다. 새로 데이터를 적재할 때 동일한 메시지 키가 있을 경우 데이터가 업데이트되었다고 볼 수 있는데, 이유는 메시지 키의 가장 최신 레코드가 추가되었기 때문이다.
KTable과 동일하게 메시지 키를 기준으로 묶어서 사용한다. 하지만 KTable은 선언된 토픽은 1개 파티션 1개 Task에 할당되어 사용되지만, GlobalKTable로 선언된 토픽은 모든 파티션 데이터가 각 Task에 할당되어 사용된다는 차이점이 있다. KStream과 KTable을 조인하려면 반드시 코파티셔닝되어 있어야 한다. 이를 통해 각 태스크는 KStream의 레코드와 KTable의 메시지 키가 동일한 경우 조인을 수행한다.
코파티셔닝(co-partitioning) 이란?
조인을 하는 2개 데이터의 파티션 개수가 동일하고 파티셔닝 전략을 동일하게 맞추는 작업, 파티션 개수가 동일하고 파티셔닝 전략이 같을 경우에는 동일한 메시지 키를 가진 데이터가 동일한 태스크에 들어가는 것을 보장한다.
하지만 토픽들이 코파티셔닝되어 있음을 보장할 수 없기 때문에 조인을 수행하지 못하는 경우도 있다. 이럴 경우 리파티셔닝하는 과정을 거쳐야 하고 리파티셔닝 되는 과정 속에서 토픽에 기존 데이터를 중복해서 생성할 뿐만 아니라 파티션을 재배열하기 위해 프로세싱하는 과정도 거쳐야하기 때문에 번거로울 수 있다.
코파티셔닝되어 있지 않은 KStream과 데이터를 조인할 수 있는 GlobalKTable을 사용하는 것이 좋다. 하지만 단점으로는 모든 데이터를 저장하고 사용하기 때문에 스트림즈 애플리케이션의 로컬 스토리지의 사용량이 증가하고 네트워크, 브로커에 부하가 생기게 된다. 그러므로 많은 양을 데이터를 가진 토픽을 조인할 경우 리파티셔닝을 통해 KTable을 사용하는 것을 권장한다.
스트림즈 DSL로 구현할 수 있는 가장 간단한 스트림 프로세싱은 특정 토픽의 데이터를 다른 토픽으로 전달하는 것이다.
특정 토픽의 KStream 형태로 가져오려면 stream() 메서드를 사용하면 되고, KStream의 데이터를 특정 토픽으로 저장하려면 스트림즈 DSL의 to() 메서드를 사용하면 된다.
메시지 키 또는 메시지 값을 필터링하여 특정 조건에 맞는 데이터를 골라낼 때는 filter() 메서드를 사용하면 된다. filter 메서드는 스트림즈 DSL에서 사용 가능한 필터링 스트림 프로세서이다.
KTable과 KStream은 메시지 키를 기준으로 조인할 수 있다. 대부분 DB는 정적으로 저장된 데이터를 조인하여 사용했지만 카프카에서는 실시간으로 들어오는 데이터들을 조인할 수 있다. KTable과 Kstream이 코파티셔닝되어 있지 않은 상태에서 join을 하게되면 TopologyException이 발생한다. 그러므로 토픽을 생성할 때 동일한 파티션 개수, 동일한 파티셔닝을 사용하는 것이 중요하다.
코파티셔닝이 되어있지 않은 토픽을 조인해야 할 때는 GlobalKTable을 사용하는 것이 좋다.
프로세서 API는 스트림즈 DSL보다 투박한 코드를 가지지만 토폴로지를 기준으로 데이터를 처리한다는 관점에서는 동일한 역할을 수행한다.
Streams DSL
Processor API