Skip to main content

11. 스트림 프로세싱

카프카의 스트림 프로세싱에 대하여 학습해봅시다.

서론#

  • 카프카는 이벤트 스트림을 전달할 수 있는 강력한 메시지 버스로 알려져있습니다.

  • 스트림 프로세싱 시스템의 완벽한 데이터 소스가 될 수 있습니다. ( 카프카 스트림즈에서는 메시지나 데이터를 이벤트라 부릅니다. )

  • 이번 챕터에서는 스트림 프로세싱의 기본 개념과 모든 프로세싱 시스템에 사용되는 디자인 패턴에 대하여 살펴볼 예정입니다.

스트림 프로세싱이란?#

  • 스트림 프로세싱의 진정한 의미에 대해서는 여전히 논란이 있습니다.

  • 이는 마치 RDBMS 세계에서 그랬던 것 처럼, DB 엔진들의 구현과 제약이 조금씩 달라서 관계형 모델의 추상적인 정의에 혼선을 초래하는 것과 같이 스트림 프로세싱 역시 저마다 정의가 다릅니다.

  • 스트림 프로세싱의 세계는 여전히 진화중이며 모든 스트림 프로세싱 시스템이 저마다의 구현과 제약이 존재합니다.

  • 이벤트 스트림은 무한 데이터세트를 나타내는 추상 개념이라 할 수 있습니다.

  • 즉 끊임없이 새로운 데이터가 전달된다는 뜻이지요. ( 계속해서 데이터가 흘러가는 것을 상상해보세요. )

  • 이러한 이벤트 스트림에는 다음과 같은 속성이 존재합니다.

이벤트 스트림에는 순서가 존재한다#

  • 본질적으로 이벤트란 다른 이벤트의 전, 후에 발생합니다.

  • 예금 이벤트를 예를들어, 계좌에 돈을 먼저 입금하고 이후에 찾는 것과, 먼저 돈을 빌리고 추후에 부채 상환을 위해 나중에 입금하는 것은 엄연히 순서에 따라 의미가 다릅니다.

  • 후자는 초과 인출이 발생하지만 전자는 그렇지 않습니다.

  • 관계형 데이터베이스의 경우 항상 순서가 없는 것으로 간주하지만, 이벤트 스트림은 명확한 순서가 존재합니다.

불변 데이터 레코드#

  • 이벤트 자체는 일단 발생하면 변경될 수 없습니다.

  • 배달을 시켰는데 취소를 할 경우, 배달에 대한 이벤트는 발행되며 이후 취소에 대한 이벤트가 발행되는 식입니다.

  • 이것이 이벤트 스트림과 데이터베이스 테이블의 또 다른 점이기도 합니다.

  • DB에서는 레코드를 삭제하거나 변경할 수 있지만, 그것은 모두 DB 내부에서 처리되는 트랜잭션이며 테이블 자체에 수록되지는 않습니다.

  • 반면에 이벤트 스트림에서는 스트림 자체에 모든 트랜잭션이 수록됩니다.

  • 레코드를 테이블에 추가 후 삭제하면 테이블에는 더 이상 레코드가 없지만 대신 redo 로그에서 두 개의 트랜잭션(추가, 삭제)를 포함합니다.

이벤트 스트림은 재생 가능할 수 있다#

  • 이벤트 스트림은 재생이 가능합니다. (소켓을 통해 전송되는 TCP 패킷 스트림은 재생이 불가능)

  • 대부분의 비즈니스 애플리케이션의 경우 수개월 전에 발생했던 이벤트 스트림을 재생할 수 있는 것이 중요합니다.

  • 이는 에러를 수정하거나 스트림의 새로운 분석 방법을 시도하거나, 감사를 수행하기 위함입니다.

  • 카프카가 성공적으로 스트림 프로세싱을 했다고 믿는 이유가 바로 여기에 있습니다.

  • 카프카는 이벤트 스트림을 캡처하고 재생할 수 있기 떄문입니다.

  • 만약 이런 능력이 없다면 스트림 프로세싱은 한낱 실험실의 장난감에 불과하겠지요.

다른 프로그래밍 패러다임과의 차이#

  • 스트림 프로세싱은 하나 이상의 이벤트 스트림을 처리하는 것을 의미합니다.

  • 스트림 프로세싱은 요청-응답, 배치 프로세스처럼 프로그래밍 패러다임의 일종입니다.

  • 스트림 프로세싱의 이해도를 높이기 위해 다른 프로그래밍 패러다임과 비교해보겠습니다.

요청 응답#

  • 1밀리초 이하에 수 밀리초까지의 짧은 응답 시간을 가집니다.

  • 애플리케이션이 요청을 전송한 후 프로세싱 시스템의 응답을 기다려야합니다.

  • DB에서는 이 패러다임이 OLTP(Online Transaction Processing)으로 알려져 있습니다.

배치 프로세싱#

  • 지연이 많지만, 처리량이 방대합니다.

  • 이 프로세싱 시스템은 설정된 시간에 시작됩니다. 가령 매일 새벽 2시, 매 시간 등이 여기에 해당합니다.

스트림 프로세싱#

  • 연속적이며 중단되지 않는 패러다임이며, 요청-응답과 배치 프로세싱 간의 격차를 줄여줍니다.

  • 대부분의 프로세스는 수밀리초 이내의 즉시 응답을 요구하지 않지만, 그렇다고 다음 날까지 기다려주지도 않습니다.

  • 또한 대부분의 비즈니스 프로세스는 연속적으로 발생합니다.

  • 물품 배달 추적, 신용카드 거래 사용 내역의 알림, 수요와 공급에 기반을 둔 실시간 가격 조정 등과 같은 비즈니스는 지속적이지만 중단되지 않는 프로세싱에 해당합니다.

스트림 프로세싱의 정의#

  • 결국 무한 데이터세트로부터 계속해서 데이터를 읽고, 처리하고, 출력을 내보낸다면 그 자체로 스트림 프로세싱입니다.

  • 단 지속적으로 계속 진행되는 것이어야 한다. 예를 들어 매일 오전 2시에 시작해서 스트림으로부터 500개의 레코드를 읽고 결과를 출력한 후 종료한다면 그것은 스트림 프로세싱이라고 보기는 어렵습니다.

스트림 프로세싱 개념#

  • 스트림 프로세싱만의 고유한 핵심 개념들에 대하여 공부해봅시다.

시간#

  • 시간은 스트림 프로세싱의 가장 중요한 개념이자 가장 혼란스러운 개념입니다.

  • 스트림 프로세싱에는 다음과 같은 시간 개념들이 존재합니다.

이벤트 시간#

  • 이벤트가 발생하여 레코드가 생성된 시간입니다.

  • 카프카는 자동으로 프로듀서 레코드에 생성 시간을 추가하고 있습니다.

로그 추가 시간#

  • 이벤트가 카프카 브로커에 전송되어 저장된 시간입니다.

  • 카프카 브로커는 자동으로 수신한 레코드에 생성 시간을 추가하고 있습니다.

  • 스트림 프로세싱에서는 이벤트 발생 시간이 관심사이므로 로그 추가 시간은 덜 중요합니다.

처리 시간#

  • 스트림 프로세싱 애플리케이션이 처리를 수행하기 위해 이벤트를 받은 시간입니다. (컨슈머가 메시지를 받은 시간)

  • 이 시간 개념은 신뢰성이 매우 낮습니다. 왜냐하면 같은 애플리케이션의 두 쓰레드에서도 다를 수 있고, 언제 읽었는지는 항상 달라질 수 있으므로 신뢰하지 맙시다.

시간대에 대한 염두#

  • 시간을 사용할 때는 타임존이 중요한데요, 왜냐하면 모든 스트림 시간에 단일 타임존을 적용해야하기 때문입니다.

  • 그래서 보통은 레코드 자체에 시간대를 저장하는 경우도 있다고 합니다.

상태#

스크린샷 2021-07-22 오전 12 42 29
  • 카프카에서 온라인 쇼핑 트랜잭션 스트림을 읽어 1만달러 이상의 트랜잭션들을 찾은 후, 판매 담당자에게 메일을 보내는 것은 컨슈머와 SMTP를 사용하면 몇 줄의 코드로 끝납니다.

  • 그러나 다수의 이벤트가 포함되는 작업을 갖는 스트림 프로세싱은 복잡합니다.

  • 현재의 한 시간동안 발생한 각 타입의 이벤트 수, 조인과 합계 평균을 구해야하는 이벤트들을 구할 때 필요한 정보가 바로 상태 입니다.

  • 스트림 프로세싱 상태에는 다음과 같은 유형의 상태가 있습니다.

로컬 또는 내부 상태#

  • 스트림 프로세싱 애플리케이션의 특정 인스턴스에서만 사용할 수 있는 상태입니다.

  • 상태는 애플리케이션 내부에 포함되어 메모리에서 실행되는 DB를 사용해 유지관리됩니다.

외부 상태#

  • 카산드라와 같은 NoSQL 외부 데이터 스토어같은 다른 시스템에 저장되고 유지 관리되는 상태입니다.

  • 대부분의 스트림 프로세싱 애플리케이션에서는 외부 데이터스토어의 사용을 피하거나 데이터를 로컬 캐시에 유지관리하여 외부 시스템과의 통신을 최소화하려고 합니다. (지연 되므로)

스트림과 테이블의 이원성#

  • 테이블에서의 레코드는 변경의 최종 결과 상태를 포함합니다.

  • 스트림은 변경을 일으키는 각 이벤트가 포함된 문자열입니다.

  • 테이블을 스트림으로 변경하기 위해서는 테이블을 수정하는 모든 이벤트를 받아서 스트림에 저장해야합니다.

  • 이를 위해 데이터 캡처(Change Data Capture, CDC) 솔루션을 제공합니다.

  • 스트림 프로세싱에 사용할 수 있도록 그런 변경 사항들을 카프카로 전달할 수 있는 카프카 커넥터들이 많습니다.

  • 반대로 스트림을 테이블로 변환하기 위해서는 스트림이 포함하는 모든 변경사항을 테이블에 적용해야하며, 이를 스트림의 구체화(materializing)이라 합니다.

  • 메모리, 내부 상태 저장소, 외부 DB 중 하나에 테이블을 생성하고, 스트림의 처음부터 끝까지 모든 이벤트를 읽어서 상태를 변경합니다.

타임 윈도우#

  • 대부분의 스트림 작업은 타임 윈도우로 수행됩니다.

  • 이 타임 윈도우를 적용할 때 고려해야할 점들이 있습니다.

타임 윈도우의 크기#

  • 모든 이벤트의 평균을 매 5분 또는 15분 도는 하루 중의 어떤 타임 윈도우로 산출할 것인지를 결정해야합니다.

  • 타임 윈도우가 커지면 지연도 커집니다.

타임 윈도우의 이동 빈도#

  • 5분의 타임 윈도우로 산출된 이동 평균을 매분, 매초 또는 새로운 이벤트의 발생 중 언제 변경할 것인가를 고려합니다.
스크린샷 2021-07-22 오전 12 23 58
  • 타임 윈도우가 스트림을 따라 진행하는 진행 간격 시간이 타임 윈도우 시간과 같다면 텀블링 윈도우라고 하며, 다른 경우를 호핑 윈도우라고 합니다.

타임 윈도우의 이벤트 변경 가능 시간#

  • 예를 들어, 00:00 ~ 00:05 (오전 0시부터 오전 0시 5분까지) 진행한다면, 한 시간이 지난 후, 00:02(오전 0시 2분)의 이벤트 시간에 추가될 결과값을 얻게되었다면 어떻게 해야할까요?

  • 이상적으로는 이벤트가 추가되는 특정 시간대의 타임 윈도우를 정의할 수 있다. 가령, 이벤트를 4시간 늦게까지 받는다면 그것으로 산출되는 결과값을 다시 계산하여 변경하고, 4시간 이후의 이벤트는 무시해버린다던지 할 수 있습니다.

스트림 프로세싱 디자인 패턴#

  • 모든 스트림 프로세싱 시스템은 서로 다릅니다.

  • 컨슈머와 프로세싱 로직 및 프로듀서를 조합한 것이 있는가 하면, 머신 러닝 기반의 스파크 스트리밍처럼 클러스터가 수반되는 것들도 있습니다.

  • 스트림 프로세싱 시스템에는 기본적인 디자인 패턴들이 있으며 이것들은 스트림 프로세싱 아키텍처의 공통적인 요구사항에 대한 솔루션으로 알려져 있습니다.

  • 잘 알려진 몇 가지 패턴을 보고 어떻게 사용되는지 살펴봅시다.

단일 이벤트 프로세싱#

  • 가장 기본적인 스트림 프로세싱 입니다.

  • 각 이벤트를 별개로 처리하는 것입니다.

  • 이 패턴의 스트림 프로세싱 애플리케이션은 스트림으로부터 이벤트를 읽고 변경한 후 다른 스트림으로 씁니다.

로컬 상태를 사용한 스트림 프로세싱#

스크린샷 2021-07-22 오전 1 00 10
  • 카프카 스트림의 상태 정보를 로컬에 저장해놓고 사용할 수 있습니다.

  • 가령 당일의 주식 최저가와 최고가를 산출하기 위해 스트림의 모든 가격들을 차례대로 비교해야 하는 경우 로컬 상태를 사용할 수 있습니다.

  • 같은 주식 종목의 모든 이벤트를 카프카의 같은 파티션에 쓰도록 하고, 애플리케이션의 각 인스턴스에서 자신에게 할당된 파티션들의 모든 이벤트를 가져오면 됩니다.

  • 애플리케이션의 각 인스턴스가 자신에게 할당된 파티션에 지정된 주식 종목의 상태를 유지관리할 수 있다는 의미입니다.

다단계 프로세싱#

스크린샷 2021-07-22 오전 1 04 52
  • 가령 매일 상위 10개의 주식을 알아야 한다면 어떤 패턴을 적용해볼 수 있을까요?

  • 로컬 상태를 갖는 각 인스턴스에서 각 종목별 주가 상승/하락을 산출한 후 새로운 토픽으로 하나의 파티션에 씁니다.

  • 그리고 이 파티션을 하나의 애플리케이션 인스턴스가 읽어서 당일의 상위 10개 주식을 알 수 있는 것이지요.

카프카 스트림즈#

  • 카프카 스트림즈 라이브러리가 실제로 동작하는 방법을 더 잘 이해하기 위해 API 내부 메커니즘을 알아봅시다.

토폴로지 생성하기#

스크린샷 2021-07-22 오전 1 07 10
  • 모든 스트림 애플리케이션은 최소 하나의 토폴로지를 구현하고 실행합니다.

  • 토폴로지는 모든 이벤트가 입력에서 출력으로 이행하는 동안 수행되는 작업과 변환 처리의 집합을 나타냅니다.

  • 간단한 애플리케이션도 나름의 토폴로지가 존재합니다.

  • 토폴로지는 프로세서들로 구성되며, 그것들은 토폴로지 그래프의 노드에 해당합니다.

  • 대부분의 노드에서는 필터와 맵과 같은 데이터 처리 작업을 구현합니다.

  • 토픽으로부터 데이터를 읽어 전달하는 소스 프로세서도 존재합니다.

  • 이전의 프로세서로부터 데이터를 받아 토픽에 쓰는 싱크 프로세서도 존재합니다.

  • 토폴로지는 하나 이상의 소스 프로세서로 시작해 싱크 프로세서로 끝납니다

토폴로지 규모 확장하기#

스크린샷 2021-07-22 오전 1 22 17
  • 카프카 스트림즈는 하나의 애플리케이션 인스턴스 내부에 다수의 실행 스레드를 허용하고, 분산된 애플리케이션 인스턴스 간의 load balancing을 지원함으로써 규모를 확장합니다.

  • 카프카 스트림즈 엔진은 토폴로지의 실행을 태스크로 분할하여 병행 처리합니다.

  • 태스크의 개수는 애플리케이션이 처리하는 토픽의 파티션 개수에 따라 카프카 스트림즈가 결정합니다.

  • 각 태스크는 전체 파티션 중 일부를 처리하는 책임을 갖습니다.

  • 애플리케이션이 생성하는 태스크들의 일부로 모든 스레드가 실행될 수 있습니다.

  • 만약 애플리케이션의 여러 인스턴스가 다수의 서버에서 실행중이라면, 서로 다른 태스크들이 각 서버의 스레드로 실행됩니다.

  • 스트리밍 애플리케이션이 구모를 확장할 수 있는 방법이 바로 이것입니다.

스크린샷 2021-07-22 오전 1 33 49
  • 스트림 프로세싱 태스크는 다수의 스레드와 서버에서 실행될 수 있습니다.

리파티션#

스크린샷 2021-07-22 오전 1 38 57
  • 애플리케이션에 따라 리파티션이 필요한 경우에 태스크간 의존 관계가 생길 수 있습니다.

  • 모든 이벤트는 유저 ID를 키로 갖는다고 가정해보겠습니다.

  • 그런데 유저가 아닌 페이지별로 통계를 구성해야한다면? 이메일 별로 생성해야한다면?

  • 예를 들어, 태스크 1이 파티션 1의 이벤트를 처리하고 그것을 리파티션하는 프로세서에 전송하여 쓰게 한 후 그것을 다른 태스크가 읽어서 처리하게 할 수 있습니다.

  • 카프카 스트림즈는 새로운 키와 파티션을 갖는 새로운 토픽에 이벤트를 쓰고, 다른 태스크들이 새로운 토픽의 이벤트를 읽고 계속해서 처리해나갑니다.

  • 리파티션을 할 때는 두 번 째 서브토폴로지는 첫 번째 서브토폴로지의 결과를 처리하므로 첫 번째 서브토폴로지에 의존성을 갖습니다.

  • 그러나 첫 번째 태스크 와 두 번째 태스크는 독립적이며 병행으로 실행될 수 있습니다.

  • 왜냐면 첫 번째 태스크는 토픽에 이벤트를 쓰고, 두 번째 태스크는 토픽의 이벤트를 읽어서 처리하기 때문이죠.

  • 두 태스크는 상호 통신하지 않으며, 공유 자원도 상요하지 않으므로 같은 스레드나 서버에서 실행될 필요가 없습니다.

장애에서 살아남기#

  • 애플리케이션의 규모를 확장하게 해주는 앞의 토폴로지에서도 장애를 처리할 수 있습니다.

  • 애플리케이션에 장애가 생겨 다시 시작해야할 때 카프카 스트림즈의 마지막 위치를 찾을 수 있고, 장애가 생기기 전 커밋했던 마지막 오프셋부터 처리가 가능합니다.

  • 로컬 상태를 저장한 데이터 스토어가 유실된 경우라면 카프카에 저장된 변경 로그를 사용해 스트림 애플리케이션이 항상 다시 생성할 수 있습니다.

  • 카프카 스트림즈는 태스크의 높은 가용성을 제공하기 위해 카프카의 컨슈머 조정도 해줍니다.

  • 하나의 태스크에 장애가 생기면, 스트림 애플리케이션의 실행 가능한 스레드나 다른 인스턴스가 있다면 사용 가능한 스레드에서 해당 태스크가 다시 실행됩니다.

  • 이것은 커슈머 그룹이 컨슈머 중 하나의 장애를 처리하는 것과 유사합니다.

스트림 프로세싱 이용 사례#

  • 이 장 앞에서도 이야기 헀듯이, 이벤트가 빨리 처리되길 원하지만 그렇다고 수밀리초까진 아닐 때 스트림 프로세싱은 유용합니다.

  • 지금부터는 실제 시나리오를 몇 가지 알아보겠습니다.

고객 서비스#

  • 대형 호텔과 같이 객실을 예약하고 확인 이메일과 영수증을 전송해야하는 경우에 사용해볼 수 있습니다.

  • 실시간 서비스에 스트림즈를 사용해볼 수 있습니다.

사물 인터넷#

  • 집안의 온도를 조정하고 세탁기의 세제 보충을 지시하는 등의 IOT 기기들에 명령 이벤트를 처리하는데 사용할 수 있습니다.

부정 적발#

  • 이상 탐지(anomaly detection)이라고 부르는 시스템에 해를 끼치는 사람을 알아낼 때 역시 스트림즈를 사용해볼 수 있습니다.

  • 신용카드 부정 사용, 주식 거래 부정 적발 등과 같은 곳에서 말이죠.

스트림 프로세싱 프레임워크를 사용하는 애플리케이션의 유형#

  • 스트림 프로세싱 프레임워크를 선택할 때 우리가 작성하려는 애플리케이션의 유형을 고려해봐야 합니다.

  • 애플리케이션의 유형은 다음과 같습니다.

ingest#

  • 하나의 시스템에서 다른 시스템으로 전달하는 목적.

  • 전달받는 시스템에 맞춰 데이터를 변경해야합니다.

low milliseconds actions#

  • 즉시 응답을 요구하는 애플리케이션.

asynchronous microservices#

  • 마이크로서비스는 더 큰 프로세스를 대신하여 작은 액션을 수행합니다.

  • 애플리케이션의 성능을 향상시키기 위해 이벤트를 캐싱하는 방법으로 로컬 상태를 유지 관리 해볼 수 있습니다.

near real-time data analytics#

  • 실시간에 가까운 데이터 분석을 위해 복잡한 집계와 조인을 사용하려는 경우.

카프카 프레임워크 선택 기준#

operability of the system#

  • 업무용 배포가 쉬운지? 모니터링과 문제 해결이 쉬운지? 규모의 확장이나 축소가 용이한지? 기존 구조와 잘 통합될 수 있는지?

makes hard things easy#

  • 대부분의 시스템에서는 진보된 타임 윈도우를 집계해줄 수 있고 로컬 캐시를 지원한다고는 합니다.

  • 그러나 그런 일들을 정말로 쉽게 해주는지? 시스템의 규모 조정과 복구와 같이 세부적인 것들을 처리해주는지 확인해보아야합니다.

community#

  • 스트림 프로세싱 애플리케이션이 오픈소스에서 얼마나 활발하게 커뮤니티가 형성되어있는지를 잘 봐야합니다.

요약#

  • 스트림 프로세싱이 무엇인지에 대해 알아보았습니다.

  • 스트림 프로세싱의 중요한 개념과 디자인 패턴들에 대하여 공부했습니다.

  • 스트림즈 아키텍처의 개요를 보았고 내부적으로 어떻게 동작하는지도 살펴보았습니다.

  • 마지막으로 스트림 프로세싱 이용사례를 보고 서로 다른 스트림 프로세싱 프레임워크를 비교 선택하는 방법도 알아보았습니다.

계정 개발팀 모두들 스터디 하느라 다들 수고 많으셨습니다!!

Reference#

스크린샷 2021-04-28 오후 7 39 45

카프카 핵심 가이드

Last updated on