데이터 중심 애플리케이션 설계 - 11장

공상현 (Kong Sang Hyean)·2024년 8월 12일
0

K DEVCON DDIA STUDY

목록 보기
11/12

😊 Go to Learn이란?

K-devcon에서 주최하는 멘토링 프로그래밍으로 각 분야에서 전문가이신 멘토분들의 멘토링을 통하여 약 2-3달간 진행하는 프로그램입니다.

Go to Learn 1기 같은 경우 Flutter, Back-end, Full-stack, Writing 등 여러가지 주제가 담긴 멘토링 프로그램이 있었습니다.

그 중 Back-end를 중심으로 진행하는 DDIA 프로그램 같은 경우 데이터 중심 애플리케이션 설계라는 책을 매주 1장 씩 정독하고 요약하면서 괸련된 이야기를 논의하면서 진행하고 있습니다.

K-devcon 이란? : IT 정보를 공유하거나 위에서 설명한 Go to Learn 스터디 및 밋업을 개최하는 활동을 하고있는 IT 커뮤니티입니다.
K-devcon 홈페이지 바로가기


📖 11장 요약 및 정리

스트림 처리의 기본 개념은 매 초가 끝나는 시점을 기준으로 그 분량의 데이터를 처리하는 것 처럼 고정된 시간 조각이라는 개념을 완전히 버리고 이벤트가 발생할 때 마다 처리해야 하는 방식이다.

이벤트 스트림

이벤트 : 스트림 처리 문맥에서 레코드를 불리운다.

  • 특정 시점에 일어난 사건에 대한 세부 사항을 포함하는 작고 독립된 불변 객체라는 점은 동일
  • 생산자가 이벤트를 만들면 해당 이벤트를 복수의 소비자가 처리한다.
  • 관계형 데이터베이스는 트리거 기능을 이용하여 이벤트 처리를 지원한다.

메시징 시스템

새로운 이벤트에 대해 소비자에게 알려주려고 쓰이는 일반적인 방법이 메시징 시스템을 사용하는 것이다.

발행 / 구독 (pub/sub)

  • 생산자가 소비자가 메시지를 처리하는 속도보다 빠르게 메시지를 전송한다면 배압흐름 제어를 이용하여 처리 속도 및 메시지 전송 속도를 조절한다.
    • 브로커는 버퍼 크기가 넘는 오래된 메시지를 자연스럽게 버린다.
    • 위의 방법은 해당 소비자만 영향을 받을 뿐 다른 소비자의 서비스가 망치지 않으므로 좋은 방법이지만 전통적인 메시지 브로커와 대조적이다.
  • 노드가 죽거나 일시적으로 오프라인이 되는 경우 지속성을 가질려면 디스크에 기록하거나 복제본 생성을 진행해야한다.

메시지 브로커 (메시지 큐)

  • 메시지 브로커는 메시지 스트림을 처리하는데 최적화된 데이터베이스의 일종이다.
  • 많은 메시지 시스템은 네트워크로 직접 통신하므로 이러한 시스템의 대안으로 사용되는 방법 중 하나이다.
  • 생산자는 브로커로 메시지를 전송하고 소비자는 브로커에서 메시지를 읽어 전송받는다.
  • 비동기로 동작한다.

복수 소비자

  • 로드 밸런싱 : 각 메시지는 소비자 중 하나로 전달된다. (처리를 병렬화하기 위해 소비자를 추가시키고 싶을 떄 유용)
  • 팬 아웃 : 각 메시지는 모든 소비자에게 전달되어진다. (독립적인 소비자가 서로 간섭 없이 청취할 수 있다.)

확인 응답

  • 생산자가 메시지를 소비자에게 전달하였지만 소비자가 메시지를 잃어버리지 못하게 사용한다.
  • 소비자의 응답을 받기 전 타임아웃 & 연결이 닫힐 경우 다른 소비자에게 전송한다.
  • 메시지가 서로 독립이라면 문제가 되지 않는 방법이지만 인과성이 있는 경우 문제가 발생하는 방법이다.

로그를 사용한 메시지 저장소

로그 기반 메시지 브로커 : 데이터베이스의 지속성 있는 저장 방법과 메시징 시스템의 지연 시간이 짧은 알림 기능을 조합한 메시지 브로커이다.

오프셋 : 각 파티션 내에서 브로커는 모든 메시지에 오프셋이라고 부르는 단조 증가하는 순번을 부여한다.

  • 파티션 내의 순번을 부여하기 때문에 다른 파티션 간 메시지의 순서는 보장하지 않는다.
  • 단일 리더 데이터베이스 복제에 널리 쓰이는 로그 순차 번호와 많이 유사하다.

메시지 단위로 병렬화 처리하고 싶지만 순서가 중요하지 않다면 JMS/AMOP 방식의 메시지 브로커가 적합하지만, 처리량이 많고 속도가 빠르지만 순서가 중요하다면 로그 기반이 효과적이다.

디스크 공간 사용

  • 저장 된 로그는 버퍼 내로 저장이 이루어진다.
  • 원형 버퍼 (링 버퍼) : 버퍼가 가득 차면 오래된 메시지 순서대로 버리는 방식
  • 기본적으로 메모리에 메시지를 유지하고 큐가 커질 때 디스크에 기록하는 메시징 시스템과 반대이다.

데이터베이스와 스트림

이벤트에서 발생한 사건은 사용자 활동이나 측정 판독일 수 있지만 데이터베이스에 기록하는 것일 수 있다.

시스템 동기화 유지

어디서든 관련이 있거나 동일한 데이터가 여러 다른 장소에서 나타나기 때문에 서로 동기화가 필수이다.

이중 기록 : 데이터가 변할 때마다 애플리케이션 코드에서 명시적으로 각 시스템에 기록한다.

  • 데이터베이스 전체를 덤프하는 작업이 너무 느리면 대안으로 사용되어진는 방법 중 하나이다.
  • 경쟁 조건이나 한 쪽 쓰기가 성공할 때 다른 쪽 쓰기가 실패할 수 있는 단점이 있다.

변경 데이터 캡쳐

변경 데이터 캡처 : 데이터베이스에 기록하는 모든 데이터의 변화를 관찰하여 다른 시스템으로 데이터를 복제할 수 있는 형태로 추출하는 과정

  • 데이터가 기록되자마자 변경 내용을 스트림으로 제공할 수 있으면 유용하다.
  • 파생 데이터 시스템(로그 소비자)은 변경 스트림의 소비자이다.

변경 데이터 캡쳐의 구현

  • 본질적으로 변경 사항을 캡쳐할 데이터베이스 하나를 리더로 하고 나머지를 팔로워로 진행한다.
  • 구현하는 또 다른 방법은 데이터베이스 트리거를 사용하는 방법이다.
  • 복제 로그를 파싱하는 방법도 있다.
    • 트리거를 사용하는 방법보다 견고한 방식이다.

전체 로그 히스토리가 없다면 일관성 있는 스냅숏을 사용해야한다.

  • 스냅숏 같은 경우 변경 로그의 위치나 오프셋에 대응되어야한다.
  • 로그 컴팩션 : 히스토리 양을 제한한다면 시스템을 추가할 때 마다 스냅숏을 만들어야하는 데 위를 위한 대안이다.
    • 해시 색인 : 주기적으로 같은 키의 로그 레코드를 찾아 중복을 제거하고 각 키에 대해 가장 최근에 갱신된 내용만 유지한다.
    • 툼스톤 : 특별한 널 값으로 갱신하는 것으로 키의 삭제를 대신 의미하는 방법도 있다.

이벤트 소싱

이벤트 소싱 : 스트리밍 시스템에 관련한 유용한 아이디어를 포함한다.

  • 애플리케이션 상태 변화를 모두 변경 이벤트 로그로 저장한다.
  • 변경 데이터 캡쳐와 가장 큰 차이점은 아이디어를 적용하는 추상화 레벨이 다르다.
    • 변경 데이터 캡쳐 : 데이터베이스를 변경 가능한 방식으로 사용하여 레코드를 자유롭게 갱신하고 삭제
    • 이벤트 소싱 : 이벤트 로드에 기록된 불변 이벤트를 기반으로 명시적으로 구축 (추가만 가능)
  • 데이터 모델링에서 쓸 수 있는 강력한 기법이다. (불변 이벤트로 기록)
  • 연대기 데이터 모델 & 별 모양 스키마과 유사하다.

이벤트 소싱을 사용하는 애플리케이션은 시스템에 기록한 데이터를 표현한 이벤트 로그를 가져와 사용자에게 보여주기에 적당한 애플리케이션 상태로 변환해야한다.

이벤트와 명령

  • 사용자 요청이 처음 도착했을 때 이 요청은 명령이다. 이 시점에서 명령은 실패할 수 있다.
  • 애플리케이션은 먼저 명령이 실행 가능한지 확인해야한다. 무결성이 검증되고 명령이 승인된다면 지속성 있는 불변 이벤트가 된다.
  • 이벤트는 생성 시점에 사실이 된다.

불변 이벤트

  • 불변성 원리는 이벤트 소싱과 변경 데이터 캡쳐를 매우 강력하게 만든다.
  • 모든 변경 로그는 시간이 지남에 따라 바뀌는 상태를 말한다.
  • 불변 이벤트는 문제 상황의 진단과 복구과 쉽다. 또한 현재 상태보다 훨씬 많은 정보를 포함한다.

명령과 질의 책임의 분리

  • 불변 이벤트 로그에서 가변 상태를 분리하면 동일한 이벤트 로그로 다른 여러 읽기 전용 뷰를 만들 수 있다.
  • 데이터를 쓰는 형식과 읽는 형식을 분리하게 된다면 상당한 유연성을 얻을 수 있다.

이벤트 소싱과 변경 데이터의 단점 중 하나인 비동기 처리를 해결하는 방법은 읽기 뷰의 갱신과 로그의 이벤트를 추가하는 작업을 동기식으로 수행하는 방법이다. (동시성 제어)


스트림 처리

스트림을 처리하는 방법

  • 이벤트에서 데이터를 꺼내 저장소 시스템에 기록하고 다른 클라이언트가 이 시스템에 해당 데이터를 질의
  • 이벤트를 사용자에게 직접 보낸다.
  • 하나 이상의 입력 스트림을 처리애 하나 이상의 출력 스트림을 생산
    • 연산자 (작업) : 스트림을 처리하는 코드 조각

스트림 처리의 사용

복잡한 이벤트 처리 : 1990년대에 이벤트 스트림 분석용으로 개발된 방법

  • CEP를 이용하여 스트림에서 특정 이벤트 패턴을 찾는 규칙을 규정할 수 있다.
  • 질의는 오랜 기간 저장되고 입력 스트림으로 들어오는 이벤트는 지속적으로 질의를 지나 흘러가면서 이벤트 패턴에 매칭되는 질의를 찾는다.

스트림 분석 : 대량의 이벤트를 집계하고 통계적 지표를 뽑는 것을 우선한다.

  • 집계 시간 간격을 윈도우라고 정의한다.
    • 텀블링 윈도우 : 크기가 고정되어있다.
    • 홉핑 윈도우 : 크기가 고정되어있지만 윈도우를 중첩할 수 있다.
    • 슬라이딩 윈도우 : 각 시간 간격 사이에서 발생한 모든 이벤트를 포함한다.
    • 세션 윈도우 : 고정된 기간이 없다. 짧은 시간동안 발생한 모든 이벤트를 그룹화하여 세션 윈도우를 정의한다.

기타 스트림 처리의 사용

  • 구체화 뷰 유지하기
  • 스트림 상에서 검색하기
  • 메시지 전달과 RPC

스트림 조인

스트림 스트림 조인 (윈도우 조인) : 두 입력 스트림은 활동 이벤트로 구성하고 조인 연산자는 시간 윈도우 내에서 발생한 관련 이벤트를 검색한다.

  • 스트림 처리자가 상태를 유지해야한다.

스트림 테이블 조인 (스트림 강화) : 한 입력 스트림은 활동 이벤트로 구성하고 다른 스트림은 데이터베이스의 변경 로그로 구성한다.

  • 스트림 처리는 한 번에 하나의 활동 이벤트를 대상으로 데이터베이스에서 이벤트의 사용자 ID를 찾아 활동 이벤트에 프로필 정보를 추가해야한다.

테이블 테이블 조인 (규체화 뷰 유지) : 양쪽 입력 스트림이 모두 데이터베이스의 변경 로그이다. 이 경우 한 쪽의 모든 변경을 다른 쪽의 최신 상태와 조인한다.

  • 스트림 처리는 새로운 메시지가 도착했을 때 어떤 타임 라인을 갱신해야 하는지 알기 위해 각 사용자의 집합이 포함된 데이터베이스를 유지해야한다.

스트림의 내결함성

결과적으로 한 번 : 일괄 처리가 결함을 견디는 접근법 중 하나이다.

  • 일부 태스크가 실패할지라도 일괄 처리 작업의 결과가 아무런 문제가 없었던 작업의 결과와 동일함을 보장한다.
  • 마치 모든 레코드를 정확하게 한번만 처리한 것처럼 보인다.

마이크로 일괄 처리 : 스트림을 작은 블록으로 나누고 각 블록을 소형 일괄 처리와 같이 다루는 방법

  • 일괄 처리 크기와 같은 텀블링 윈도우를 암묵적으로 지원한다.

원자적 커밋 재검토 : 장애가 발생했을 때 정확히 한 번 처리되는 것처럼 보일려면 처리가 성공했을 때만 모든 출력과 이벤트 처리의 부수 효과가 발생해야한다.

  • 원자적으로 모두 일어나거나 또는 모두 일어나지 않아야 하지만 서로 동기화가 깨지면 안된다.

멱등성 : 여러 번 수행하더라도 오직 한 번 수행한 것과 같은 효과를 내는 연산이다.

  • 처리 효과가 두 번 나타나는 일 없이 안전하게 재처리하기 위해 실패한 부분을 버리는 방법으로 쓰인다.
  • 연산이 멱등적이지 않아도 여분의 메타데이터를 통하여 연산을 멱등적으로 만들 수 있다.

실패 후 상태 재구축 : 윈도우 집계나 조인용 테이블과 색인처럼 상태가 필요한 스트림 처리는 실패 후에도 해당 상태가 복구됨을 보장해야한다.

  • 원격 데이터 저장소에 상태를 유지하는 복제하는 방법이 있다.
  • 모든 트레이드오프는 기반 인프라 스트럭처의 성능 특성에 달려있다.

😉 필자의 생각

이번 장에는 Part 3 개요에서 설명한 데이터 처리 시스템 중 하나는 스트림 처리 시스템를 주제로 기술되어 있다. 메시징 시스템아 어떠한 구조로 되어있는지를 시작으로 데이터베이스에 기록하는 방법 그리고 스트림 처리에 대해 설명해주는 내용이 주를 이루었다.

해당 장을 읽어보면서 정리했었던 당시 AWS와 관련된 자격증을 공부하고 있었고 주제와 관련된 서비스인 SNS, SQS 같은 이벤트 스트림 서비스들이 생각이 났었다 그리서 위와 같은 서비스를 사용한 경험이 있는지 질문을 드렸었는데 처음에 각 sub topic 처리와 관련하여 SNS 서비스를 사용했었다는 이야기를 들었었다. 하지만 여러 제한들이 발생하여서 위를 해결하기 위해 다른 메시징 큐를 도입하였다는 이야기도 들었었다.

또한 실 업무에서 스트림 처리는 어떤 부분이 어려운지 논의해보았는데 메시지간 의존성과 관련하여 꽤 까다로웠다는 이야기가 나왔었다. 예를 들어 질문을 보냈는데 응답으로 질문 먼저 오는게 아니라 위의 답이 먼저 오는 문제가 있었다고 한다. 위의 문제를 해결하기 위해 스트림 처리 방법론이 등장하게 되었지만 위의 방법 같은 경우 복잡성이 늘어난다는 단점이 존재한다고 들었었다.

profile
개발자 같은 거 합니다. 1인분 하는 개발자로서 살아갈려고 노력 중입니다.

0개의 댓글