스트림 프로세싱(Stream Processing) - 2

데이터베이스와 스트림

메시지 브로커와 데이터베이스는 전혀 다른 범주의 도구로 바라볼 수 있지만 로그 기반 메시지 브로커는 데이터베이스에서 아이디어를 얻어 메시지 시스템에 적용하는데 성공하였습니다. 데이터베이스의 복제 로그(replication log)는 데이터베이스에 쓰는 이벤트 스트림으로 볼 수 있습니다.

변경 데이터 캡처(CDC, Change Data Capture)

변경 데이터 캡쳐는 데이터베이스에 기록하는 모든 데이터의 변경사항을 관찰해 다른 시스템으로 데이터를 복제할 수 있는 형태로 추출하는 과정을 말합니다. 이러한 CDC는 데이터베이스에 데이터가 기록되자 마자 변경된 내용을 스트림을 제공하면 유용하게 사용할 수 있습니다. CDC를 소비하는 다른 시스템의 예가 다음과 같습니다.

CDC는 주로 데이터베이스의 복제 로그를 파싱하여 구현합니다. 다른 방법으로는 데이터베이스의 트리거 기능을 이용하기도 합니다. 대표적인 CDC는 다음과 같습니다.

이벤트 소싱

갑자기 이벤트 소싱에 대한 설명이 나와서 의아해 할지도 모르겠습니다. 이벤트 소싱은 스트리밍 시스템과 관련한 유용한 아이디어들과 유사한 점이 많습니다. 이벤트 소싱은 도메인 주도 설계 커뮤니티에서 개발한 기법으로, CDC와 유사하게 애플리케이션 상태 변화를 모두 변경 이벤트 로그로 저장합니다.

이벤트 소싱은 애플리케이션 관점에서 사용자의 행동을 불변 이벤트로 기록합니다. 주로 추가만 가능하고 갱신이나 삭제는 권하지 않거나 금지합니다. 이러한 이벤트 소싱은 데이터 모델링에서 쓸 수 있습니다. 이러한 방식은 데이터베이스 상에 사용자의 행동에 대한 결과를 저장하는 방식보다 많은 장점을 지닙니다. 어떤 상황이 발생한 후에 상황 파악이 용이하기 때문에 디버깅에 도움이 되고 버그를 방지할 수 있습니다.

이벤트 로그 자체로는 크게 유용하지 않습니다. 일반적으로 사용자는 애플리케이션의 현재 상태를 보기 원하지 히스토리를 원하지 않기 때문입니다. 예를 들어, 쇼핑 웹 사이트에서 사용자가 장바구니에 변경 사항을 기록한 것을 보기 원하지 않고 현재 장바구니의 상태만을 보고 싶어합니다. 그래서 이벤트 소싱을 사용하는 애플리케이션은 이벤트 로그를 가져와 현재 상태를 보여주도록 변환해야 합니다.

CDC와 다른점은 CDC의 경우 레코드의 이전 버전은 로그 컴팩션을 통해 삭제가 가능하지만 이벤트 소싱에서는 로그 컴팩션이 불가능합니다. 그러나 전체 이벤트 로그를 반복해서 재처리하는 것은 비효율적이기 때문에 현재 상태에 대한 스냅샷을 저장하여 사용합니다.

CQRS(command query reponsibility segregation)

데이터베이스와 스키마 설계의 전통적인 접근법은 데이터가 질의를 받게될 형식과 같은 형식으로 데이터를 기록해야 한다는 관점에서 접근합니다. 그러나 데이터에 대해 어떻게 질의하고 접근하는지 신경을 쓰지 않는다면 데이터 저장은 상당히 직관적인 작업이 됩니다. 그렇기 때문에 데이터를 쓰는 형식과 읽는 형식은 분리해 다양한 읽기 뷰를 허용하면 유연성을 얻을 수 있습니다. 이 개념이 바로 CQRS(command query responsibility segregation)입니다.

스트림 처리하기

하나 이상의 입력 스트림을 처리해 하나의 이상의 출력 스트림을 생산합니다. 스트림은 최종 출력에 이르기 까지 여러 단계의 파이프 라인을 구성할 수 있습니다.

CEP(Complex Event Processing)

CEP는 스트림에서 특정 이벤트 패턴을 검색해야하는 애플리케이션에 적합합니다. CEP 엔진은 찾고자 하는 이벤트 질의를 저장하고 있다가 입력 스트림으로부터 들어오는 이벤트 패턴과 매칭되는지 찾습니다. 이에 반해 데이터베이스에서는 질의가 들어오면 질의와 매칭되는 데이터를 찾고 작업이 완료되면 질의를 기억하고 있지 않습니다. CEP 구현에는 Esper, IBM InfoSphere Streams, Apama, TIBCO StreamBase, SQLstream 등이 있습니다.

스트림 분석

스트림 처리를 사용하는 이유 중에 하나는 스트림을 분석하기 위함입니다. 분석을 할 때는 고정된 시간 간격을 기준으로 계산을 주로 합니다. 예를 들어 지난 5분간 서비스에 들어온 초당 질의 수의 평균을 구하거나 같은 기간 동안 99분위 응답 시간을 구하는 것입니다. 스트림 처리에서 이렇게 집계 시간 간격을 윈도우(window)라고 합니다. 많은 분산 스트림 처리 프레임워크들이 이렇게 분석 용도로 설계되었습니다.

시간에 대한 추론

스트림 처리 프레임워크에서 윈도우 시간을 결정할 때 처리하는 장비의 시계(처리 시간)를 사용합니다. 이벤트 시간의 생성 시간과 이벤트 처리 시간의 간격이 작다면 괜찮지만 처리 시간이 지연되면 문제가 발생합니다. 또한 메시지가 지연되면 메시지 순서가 뒤바뀔 수도 있습니다. 그렇기 때문에 스트림 처리 알고리즘은 그런 타이밍과 순서 문제를 잘 처리하도록 작성해야 합니다.

이벤트 시간 vs 처리 시간

이벤트 발생 시간과 처리 시간을 혼동하면 잘못된 데이터가 생길 수 있습니다. 아래의 그림의 예처럼 스트림 처리하는 애플리케이션을 재배포하면서 1분간 이벤트를 처리하지 못하다가 실행 후 백로그 이벤트들을 처리할 때, 실제 요청률은 그대로이지만 처리 시간을 기준으로 측정된 요청률은 비정상적으로 데이터가 튀는 것을 볼 수 있습니다.

뒤처진 이벤트 처리

이벤트 시간을 기준으로 윈도우를 정의하는 경우 특정 윈도우에서 모든 이벤트가 도착했다라는 것을 확신할 수 없습니다. 그렇기 때문에 윈도우가 종료된 후 도착한 이벤트를 처리할 방법이 필요한데 다음 2가지 방법이 있습니다.

이벤트 발생 시간 추정

이벤트가 발생한 머신과 이벤트를 처리하는 서버의 시간을 통해서 이벤트 발생 시간을 추정하는 한가지 방법은 다음과 같이 세 개의 타임스탬프를 로그로 남기는 것입니다.

위와 같이 세 개의 타임스탬프가 존재한다고 하면 네트워크 지연으로 인한 시간은 무시할 만하다고 가정했을 때, 서버에서 실제로 발생한 이벤트 시간을 추정할 수 있게 됩니다.

윈도우 종류

윈도우는 이벤트 수를 세거나 윈도우 내의 평균값을 구하는 등의 집계 연산을 위해 사용하는데 그 윈도우의 종류은 다음과 같습니다.

윈도우 종류

윈도우 종류

스트림 조인

스트림 처리에서도 배치 처리와 마찬가지로 조인이 필요합니다. 스트림 처리에서 조인의 유형은 다음 3가지로 구분합니다.

스트림-스트림 조인(윈도우 조인)

스트림-스트림 조인은 두 스트림으로 부터 윈도우를 구성하여 조인하는 방법입니다. 조인은 방법에 따라 다양한 조인이 있지만 여기서는 Inner 조인을 기준으로 설명합니다. 두 스트림은 윈도우 내에서 아래와 같이 조인을 할 수 있습니다.

스트림-테이블 조인

스트림 간의 조인뿐만 아니라 기존에 데이터베이스의 테이블과도 조인이 가능합니다. 예를 들어 사용자 활동 이벤트가 스트림이라고 할 때, 해당 스트림내에 존재하는 사용자 ID를 기준으로 데이터베이스로부터 사용자 프로필을 가져와서 조인할 수 있습니다. 스트림 조인을 통해서 스트림에서 필요한 정보를 추가하게 됩니다. 이 방식은 스트림 처리에서 매번 데이터베이스에 해당 정보를 요청해서 조인을 하는 방법이 있고, 테이블의 크기가 작다면 로컬에 사본을 가지고 조인을 처리할 수 있습니다. 이 경우에는 데이터베이스가 업데이트되어 변경될 수 있으니 항상 최신 상태로 유지해야 합니다. 이 경우 보통 CDC를 사용해서 처리가 가능합니다.

테이블-테이블 조인(구체화된 뷰 유지하기)

테이블-테이블 조인은 데이터베이스의 테이블끼리의 조인과 같습니다. 그러나 각각의 테이블은 다음 그림과 같이 스트림으로부터 업데이트 됩니다.

이와 같이 두 개의 테이블이 테이블 별로 스트림으로부터 갱신이 되고, 업데이트 된 테이블을 조인하여 구체화된 뷰를 유지합니다.

내결함성

마지막으로 설명한 내용은 내결함성입니다. 일반적으로 배치 처리의 경우 쉽게 결함에 대처할 수 있습니다. 맵리듀스를 예를 들어보면 하나의 태스트가 실패하면 다른 장비에서 해당 태스크를 다시 실행하고 실패한 태스크의 결과는 버리는 것입니다. 이와 같은 재처리가 가능한 이유는 입력 데이터가 불변이고 각 태스크가 성공적으로 완료되어야지 그 결과를 확인할 수 있기 때문입니다. 스트림 처리에서는 이러한 내결함성을 지원하기 위한 문제가 쉽지는 않습니다. 대표적으로 내결함성을 지원하는 방법은 다음과 같습니다.

지금까지 이벤트 스트림에 대해 설명하고 이벤트 스트림의 목적과 처리 방법에 관해 알아보았습니다. 스트림 처리는 고정 크기의 입력이 아니라 끝이 없는 스트림 상에서 연속적으로 실행되기 때문에 그에 따른 다양한 관점에서 특징들을 살펴보았습니다.

References



comments powered by Disqus