책너두 (데이터 중심 애플리케이션 설계) 41일차 (~473p)

요약

  • 스트림 처리의 나머지 부분에 대해 이해함.
    • 시간에 관한 추론
      • 이벤트 시간 대 처리 시간
      • 준비 여부 인식
      • 어쨋든 어떤 시계를 사용할 것인가?
      • 윈도우 유형
    • 스트림 조인
      • 스트림 스트림 조인(윈도우 조인)
      • 스트림 테이블 조인(스트림 강화)
      • 테이블 테이블 조인(구체화 뷰 유지)
      • 조인의 시간 의존성

메모

시간에 관한 추론

  • 시간에 관한 추론에서 스트림 처리자는 종종 시간을 다뤄야 할 때가 있으며, 이때 주로 시간 윈도우를 사용함.
    • 일괄 처리와 스트림 처리 프레임워크는 시간을 처리하는 방식에 차이가 있음.
  • 일괄 처리에서 태스크는 과거에 쌓인 대량의 이벤트를 빠르게 처리하며, 시간 단위로 쪼갤 필요가 있다면 각 이벤트에 내장된 타임스탬프를 사용함.
    • 일괄 처리를 수행하는 장비의 시스템 시계를 보는 것은 의미가 없음.
  • 반면, 많은 스트림 처리 프레임워크는 윈도우 시간을 결정할 때 처리하는 장비의 시스템 시계(처리 시간)를 이용함.
    • 이 접근법은 간단하다는 장점이 있으나, 처리가 지연되면 문제가 생김.

이벤트 시간 대 처리 시간

  • 처리가 지연되는 데는 여러 이유가 있으며, 이로 인해 메시지 순서를 예측하지 못할 수도 있음.
    • 이벤트 시간과 처리 시간을 혼동하면 좋지 않은 데이터가 만들어짐.
  • 처리 지연의 원인은 큐 대기, 네트워크 결함, 메시지 브로커나 처리자에서 경쟁을 유발하는 성능 문제, 스트림 소비자의 재시작, 결함에서 복구하는 도중이나 코드 상의 버그를 고친 후 과거 이벤트의 재처리 등이 있음.
  • 메시지가 지연되면 실제 이벤트 발생 순서와 다르게 처리될 수 있음.
    • 이로 인해 이해하기 어려운 결과가 발생할 수 있음.
    • 스트림 처리 알고리즘은 타이밍과 순서 문제를 처리하게끔 명확히 작성할 필요가 있음.
  • 예를 들어, 요청률을 측정하는 스트림 처리자가 있다면, 처리 시간을 기준으로 요청 비율을 측정하면 실제 요청률은 안정적이지만 백로그를 처리하는 동안 요청이 비정상적으로 튀는 것처럼 보임.

준비 여부 인식

  • 이벤트 시간 기준으로 윈도우를 정의할 때 발생하는 문제는 특정 윈도우에서 모든 이벤트가 도착했는지 아니면 계속 들어오고 있는지 확신할 수 없다는 점임.
  • 예를 들어 분당 요청 수를 세기 위해 1분 윈도우에 이벤트를 그룹화한다고 하면, 어떤 시점에서 해당 윈도우를 종료하고 카운트 값을 출력해야 할지 결정하기 어려움.
    • 타임아웃을 설정하고 얼마 동안 새 이벤트가 들어오지 않으면 윈도우가 준비됐다고 선언할 수 있지만, 일부 이벤트는 지연될 수 있음.
    • 이러한 낙오자 이벤트를 처리할 방법으로 크게 두 가지가 있음.
      1. 낙오자 이벤트는 무시한다.
        • 정상적인 환경에서는 낙오자 이벤트가 적은 비율을 차지하기 때문임.
        • 놓친 이벤트의 수를 지표로 추적해 데이터가 누락되는 경우 경고를 보낼 수 있음.
      2. 수정 값을 발행한다.
        • 수정 값은 낙오자 이벤트가 포함된 윈도우를 기준으로 갱신된 값임.
        • 이전 출력을 취소해야 할 수도 있음.
  • 어떤 경우에는 특별한 메시지를 사용해 "이제부터 보다 이른 타임스탬프를 가진 메시지는 없다"고 가리키기도 함.
    • 그러나 여러 생산자가 저마다 최소 타임스탬프 임계치를 가지고 이벤트를 만든다면, 소비자는 개별 생산자를 모두 추적해야 함.
    • 이 경우 생산자를 추가하거나 제거하기가 더 까다로움.

어쨌든 어떤 시계를 사용할 것인가?

  • 이벤트에 타임스탬프를 할당하는 것은 여러 지점에 버퍼링됐을 때 더 어려움.
    • 예를 들어, 오프라인일 때도 사용 가능한 모바일 앱이 사용률 지표 측정용 이벤트를 서버로 보고한다고 가정하면, 이벤트의 타임스탬프는 장치 로컬 시계를 따르는 실제 상호작용 시각이어야 함.
    • 그러나 사용자가 제어하는 장비의 시계를 항상 신뢰하기는 어려움.
  • 서버 시계를 따르는 이벤트를 서버에서 받은 시각이 정확할 수 있지만, 사용자와의 상호작용을 설명하기에는 의미가 부족함.
  • 잘못된 장치 시계를 조정하는 한 가지 방법은 세 가지 타임스탬프를 로그로 남기는 것임
    • 이벤트가 발생한 시간: 장치 시계를 따른다.
    • 이벤트를 서버로 보낸 시간: 장치 시계를 따른다.
    • 서버에서 이벤트를 받은 시간: 서버 시계를 따른다.
  • 두 번째와 세 번째 타임스탬프 차이를 구하면 장치 시계와 서버 시계 간의 오프셋을 추정할 수 있음.
    • 계산한 오프셋을 이벤트 타임스탬프에 적용해 이벤트가 실제로 발생한 시간을 추정할 수 있음.
    • 이 문제는 일괄 처리에서도 동일한 문제가 발생하며, 스트림 처리에서 이 문제가 더 두드러짐.

윈도우 유형

  • 이벤트 타임스탬프를 결정한 후, 윈도우 기간을 정의해야 함.
    • 윈도우는 이벤트 수를 세거나 평균값을 구하는 등 집계를 할 때 사용함.
    • 일반적으로 사용하는 윈도우 유형은 다음과 같다.
      1. 텀블링 윈도우(Tumbling window)
        • 텀블링 윈도우의 크기는 고정 길이임.
        • 모든 이벤트는 정확히 한 윈도우에 속함.
        • 예를 들어 1분 텀블러 윈도우가 있다고 하면, 연속된 1분 구간의 이벤트가 한 윈도우에 그룹화됨.
      2. 홉핑 윈도우(Hopping window)
        • 홉핑 윈도우는 고정 길이를 사용하며, 윈도우를 중첩할 수 있음.
        • 예를 들어 1분 크기의 홉을 사용하는 5분 윈도우가 있다고 하면, 연속된 5분 구간의 이벤트를 포함하되, 각 윈도우가 1분씩 겹침.
      3. 슬라이딩 윈도우(Sliding window)
        • 슬라이딩 윈도우는 각 시간 간격 사이에서 발생한 모든 이벤트를 포함함.
        • 예를 들어 5분 슬라이딩 윈도우가 있다면, 5분 이내에 발생한 모든 이벤트가 같은 윈도우에 포함됨.
      4. 세션 윈도우(Session window)
        • 세션 윈도우는 고정된 기간이 없으며, 같은 사용자가 짧은 시간 동안 발생시킨 모든 이벤트를 그룹화해서 세션 윈도우를 정의함.
        • 사용자가 비활성화되면(예를 들어 30분 동안 이벤트가 없으면) 윈도우를 종료함.

스트림 조인

  • 스트림 처리에서도 조인의 필요성은 동일하나, 새로운 이벤트가 언제든 나타날 수 있어 스트림 상에서 수행하는 조인이 더 어려움.
  • 스트림 조인은 크게 세 가지 유형으로 구분함
    1. 스트림-스트림 조인(stream-stream join): 두 스트림 간의 조인을 처리함.
    2. 스트림-테이블 조인(stream-table join): 스트림과 테이블 간의 조인을 처리함.
    3. 테이블-테이블 조인(table-table join): 두 테이블 간의 조인을 처리함.
  • 각 조인 유형은 다양한 예제를 통해 설명되고 있음.

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

  • 웹사이트의 검색 기능을 분석하는 예시로 설명되며, 검색 이벤트와 클릭 이벤트를 함께 모아서 처리해야 함.
    • 사용자가 검색 결과를 클릭하지 않을 수도 있고, 검색과 클릭 사이의 시간이 가변적임.
    • 조인을 위한 적절한 윈도우 선택이 필요함 (예: 한 시간 이내에 발생한 검색과 클릭을 조인).
    • 클릭 이벤트에 검색 세부 내용을 추가하는 것은 이벤트를 조인하는 것과 동일하지 않음.
    • 정확한 클릭율을 측정하려면 검색 이벤트와 클릭 이벤트가 모두 필요하다.
  • 스트림 처리자는 상태(state)를 유지해야 하며, 이벤트를 세션 ID로 색인해야 함.
    • 이벤트가 매칭되면 검색 결과를 클릭했다는 이벤트를 방출하고, 검색 이벤트가 클릭 이벤트 매칭 없이 만료되면 클릭되지 않았다는 이벤트를 방출함.

스트림 테이블 조인(스트림 강화)

  • 사용자 활동 이벤트와 사용자 프로필 데이터베이스를 조인하는 예제로 설명되며, 입력은 사용자 ID를 포함한 활동 이벤트 스트림이고 출력은 해당 ID를 가진 사용자 프로필 정보가 추가된 활동 이벤트임.
    • 데이터베이스 탐색은 원격 데이터베이스 질의로 구현할 수 있으나, 이는 느리고 데이터베이스에 과부화를 줄 위험이 있음.
    • 로컬에서 질의가 가능하도록 스트림 처리자 내부에 데이터베이스 사본을 적재하는 것이 더 효율적이다.
      • 이 기법은 해시 조인과 비슷함.
      • 로컬 사본 용량이 충분히 작으면 메모리 내 해시 테이블에 넣을 수 있고, 색인을 로컬 디스크에 넣을 수도 있음.
    • 스트림 처리자는 사용자 프로필 데이터베이스의 변경 로그를 구독하고, 프로필을 생성하거나 수정하면 로컬 복사본을 갱신함.
      • 그러면 활동 이벤트와 프로필 갱신이라는 두 개의 스트림을 조인할 수 있음.
  • 스트림-테이블 조인은 스트림-스트림 조인과 비슷하며, 가장 큰 차이점은 테이블 변경 로그 스트림 쪽은 시작 시간까지 이어지는 윈도우(개념상 무한 윈도우)를 사용하고, 레코드의 새 버전으로 오래된 것을 덮어쓴다는 점임.
    • 스트림 입력 쪽은 윈도우를 전혀 유지하지 않을 수도 있음.

테이블 테이블 조인(구체화 뷰 유지)

  • 트위터 타임라인 예제를 통해 구체화 뷰를 유지하는 방법을 설명함.
  • 사용자가 팔로우한 사람들의 최근 트윗을 찾아 병합하는 것은 비용이 많이 들기 때문에, 타임라인 캐시를 사용하여 타임라인을 읽을 때 단일 조회가 가능함.
    • 사용자별 받은 편지함과 같은 타임라인 캐시를 사용하며, 이를 구현하기 위해서는 트윗 이벤트 스트림(전송과 삭제)과 팔로우 관계 이벤트 스트림(팔로우와 언팔로우)이 필요함.
    • 스트림 처리는 새로운 트윗이 도착했을 때 어떤 타임라인을 갱신해야 하는지 알기 위해 각 사용자의 팔로우 집합이 포함된 데이터베이스를 유지해야 함.
  • 다른 방법으로는 트윗과 팔로우 두 테이블을 조인하는 질의에 대한 구체화 뷰를 유지하는 것임.
    • 이는 스트림 조인과 직접 대응되며, 결과적으로 질의 결과의 캐시가 타임라인이 되고, 조인 대상 테이블이 변할 때마다 갱신됨.

조인의 시간 의존성

  • 세 가지 조인 유형(스트림-스트림, 스트림-테이블, 테이블-테이블)에 공통점이 있으며, 스트림 처리자가 하나의 조인 입력을 기반으로 특정 상태를 유지해야 함.
  • 상태를 유지하는 이벤트의 순서는 매우 중요함.
    • 파티셔닝된 로그에서 단일 파티션 내 이벤트 순서는 보존되지만, 다른 스트림이나 다른 파티션 사이에서 순서를 보장하는 일반적인 방법은 없음.
  • 시간 의존성은 많은 곳에서 발생하며, 예를 들어 송장에 올바른 세율을 표시해야 하는 경우에 따라 다름.
  • 세율 테이블에 판매를 조인할 때, 대개 판매 시각에 맞는 세율과 조인하기를 원함. 과거 데이터를 재처리한다면 그때 세율과 현재 세율이 다를 수 있음.
    • 복수 개의 스트림에 걸친 이벤트 순서가 결정되지 않으면 조인도 비결정적임.
    • 이것은 동일한 입력으로 같은 작업을 재수행하더라도 반드시 같은 결과를 얻지는 못한다는 의미임.
  • 이 문제를 해결하는 방법 중 하나는 천천히 변하는 차원(slowly changing dimension, SCD)을 사용하는 것임.
    • 이 방법은 흔히 조인되는 레코드의 특정 버전을 가리키는 데 유일한 식별자를 사용함.
    • 변경한 조인은 결정적이지만, 테이블에 있는 레코드의 모든 버전을 보유해야 하기 때문에 로그 컴팩션이 불가능함.

댓글

Designed by JB FACTORY