data7 MIN READ

[데이터 엔지니어링 디자인 패턴] 08. 데이터 스토리지

[데이터 엔지니어링 디자인 패턴] 08. 데이터 스토리지

데이터 엔지니어링 디자인 패턴 시리즈의 글입니다.

쿼리, 작업을 더 빠르게 할 수 있도록 데이터 스토어 디자인 패턴을 사용해 현명한 데이터 구성을 해보자.

8.1 파티셔닝

데이터셋을 쉽게 접근할 수 있도록 나누는 최선의 방법이 무엇인가?

수평 파티셔너

Horizontal Partitioner Pattern 수평적구성, 가장 일반적으로 사용됨

  • 문제
    • 나흘의 롤링 집계를 계산하는 배치 잡이 있음
    • 실행시간이 오래걸리고있어, 이를 줄일 방법을 찾아야함
  • 해결책
    • 롤링집계는 데이터셋의 일부만 사용하는 증분데이터 처리의 대표 예시임
    • 해결책은 distribution key (분산 키) = 파티셔닝 속성을 식별하는것
    • 가장 일반적인것은 시간 기반 파티셔닝
    • 시간경계를 정의하여 관련 정보를 저비용으로 쿼리 가능
    • 비즈니스 경계도 간혹 파티셔닝 키로 활용됨 (ex. 고객 id, 지역, ..)
    • 멱등성의 중요한 구성요소
  • 결과
    • 세분화와 메타데이터 오버헤드
      • 파티션이 너무 많으면 db에 부정적 영향을 끼침
      • 구별되는 값이 낮은 cardinality 속성을 사용해야함
    • skew
      • 수평 파티셔닝이 균등한 데이터를 항상 보장하지는 않음
      • skewed partition은 지연 문제의 원인이됨
      • micro batch에서 한 파티션이 불균형하면, 그 지연시간이 곧 배치 전체의 지연시간이 됨.
    • 가변성
      • 파티션 키 변경이 어려움.
      • 일부스토어는 다행히 변경을 지원함. (ex. 메타데이터 계층에서만 파티셔닝..)

수직 파티셔너

Vertical Partitioner pattern

  • 문제
    • 불변 정보의 저장을 피하고자함
    • 이벤트 발생때마다 불변 정보는 한 번만 저장하고자 함
  • 해결책
    • 수직 파티셔너 패턴을 사용
    • 그룹화해야하는 데이터를 분류
    • 각 레코드에 대해 그룹화된 속성을 전용 위치에 write
    • 데이터 보존 / 접근정책을 쉽게 적용 가능.
  • 결과
    • 도메인 분할
      • 레코드가 분리되어 논리적으로 관련된 속성이 다른곳에 저장될 수 있음
      • 양질의 문서화가 필요
    • 쿼리
      • 도메인을 분할하므로, 전체 그림 파악이 어려워짐
      • 문제완화를 위해 모든 테이블을 결합한 구체화된 view를 사용할 수 있음
    • 데이터 프로듀서
      • 프로듀서에 레코드 분할 로직을 적용하여 복잡도가 높아짐
      • 잠재적으로 더 높은 네트워크 통신 비용으로 여러번의 쓰기 수행

8.2 레코드 구성

record co-location에 대한 최적화 적용 수평 파티셔너 패턴의 cardinality 문제 해결

버킷

bucket patter

  • 문제
    • 쿼리에서 자주 사용되는 특정 비즈니스 속성이 존재
    • 이 컬럼을 파티셔닝 컬럼으로 사용하고싶지만 카디널리티가 너무 높은 상황
    • 최적화하고자 함
  • 해결책
    • 쿼리에 자주 관련되는 높은 카디널리티 컬럼이 있다면 bucket pattern이 적절
    • bucketing에 사용할 컬럼을 먼저 정의 (=보조 그룹화 키 집합=버킷컬럼)
    • 버킷 수 설정
    • hash(key) % bucket number
    • 레코드 그룹화
      • bucket pruning : 필요한 키가 없는 버킷을 제거할 수 있다
      • shuffle 제거 : 저장시점에 join 기준으로 미리 분배하여 셔플(네트워크 교환)없이 결합
  • 결과
    • 가변성 : 버킷팅 스키마는 불변. 변경하게되면 백필링이 필요한 고비용 작업 필요.
    • 버킷크기 : 적절한 크기 찾기가 매우 어려움

정렬기

Sorter Pattern 쿼리와 관련 없는 데이터 블록을 제거하기 위해서는 데이터 저장 순서 역시 중요함

  • 문제
    • 주간테이블에 데이터를 저장하려고함
    • 동시에 데이터 접근 지연을 줄이고자함
    • 사용자 쿼리 유형은 알고있는 상태
  • 해결책
    • 일반적으로 사용되는 컬럼을 안다? ⇒ 정렬, 필터링이 해답
    • 테이블 생성 쿼리에서 정렬 컬럼을 선언
    • 저장속가 이미 정렬되었으므로,
    • 쿼리는 메타데이터 정보를 활용하여 관련없는 데이터 블록을 skip할 수 있음
    • 곡선정렬 (Z-order)
  • 결과
    • 미리 정렬된 데이터셋은 reader에게는 긍정적 / writer 에게는 부정적 영향을 미침
    • 정렬되지 않은 세그먼트
      • 정렬이 항상 즉각적인 활동은 아님
      • 데이터 쓰기 작업 내 or 외부에서 정렬 작업을 예약
      • ⇒ 실행시간에 영향을 미칠 수 있음
    • 복합 정렬 키
      • 쿼리가 대상으로 하는 컬럼보다 앞선 정렬 컬럼을 참조해야함
    • 가변성
      • 생성 후 정렬키 변경은 비용이 많이 듬

8.3 조회 성능 최적화

데이터 접근을 최적화하기 위해 기존 데이터 구성 기법을 확장

메타데이터 강화기

Meadata Enhancer Pattern 조회성능 최적화를 위해 메타데이터 사용을 할 수 있음

  • 문제
    • 큰 파티션때문에 클라우드 요금 증가
    • 현재는 적재 후 → 필터링 로직
    • 필터링 → 적재로 변경하고자함
  • 해결책
    • 쿼리실행 시간, 비용 최적화의 핵심 = 적제하기 전 관련없는 데이터를 skip하기
    • 메타데이터강화기구편은 각 파일에 메타데이터있는 푸터를 포함하여 저장
    • 통계는 파일에 국한됨
    • 프로듀서 파일 생성시 자동으로 계산 되는 값 범위를 포함
    • 추가로 reader 최적화 가능한 추가 메타데이터를 커밋로그에 저장
  • 결과
    • 오버헤드
      • 쓰기시점 통계구축 = writer추가작업
      • 처리시간에 영향을 줌
      • 통계 최신상태로 유지해야 의미있음
      • 오래된 통계문제 해결을 위해 refresh 실행
    • 오래된 통계
      • 통계가 자동갱신되더라도 즉시 수행은 아님
      • 결국 낙후된 통계를 사용하는 문제가 생김
      • analyze table 명령어로 통계 refresh가능
      • = 읽기 오버헤드 추가

데이터셋 구체화기

Dataset Materializer Pattern 읽기성능개선을 위해서는 데이터 중복을 활용하는게 도움이 될 수 있음

  • 문제
    • 쿼리 단순화를 위해 뷰를 생성했지만
    • 뷰가 매번 기본쿼리를 실행하고있음
    • 더 나은 성능의 단일 데이터 접근 지점을 제공하고자함
  • 해결책
    • 결과 계산이 느릴때 간단한 해결책 = 데이터를 구체화하여 문제를 피함
    • 데이터셋을 식별 → 구체화를 구현
    • 여러 데이터셋을 결합하여 Materialized view or table을 구현
    • refresh에 대한 책임을 져야함
  • 결과
    • refresh비용
      • 뷰를 refresh할때마다 쿼리 실행 비용이 듬
      • 증분 새로고침으로 완화 가능
    • 데이터 접근
      • materialized view는 여러 테이블을 결합
      • 일관된 데이터 관리가 어려움
    • 데이터 스토리지 오버헤드
      • 저장소를 위해 최적화를 절충할수있음
      • 뷰의 일부만 구체화하고 재계산 가능한부분은 재계산으로 유지하는 혼합구현으로 완화

매니페스트

Manifest Pattern 데이터 목록 작성을 통해 api 호출을 줄임

  • 문제
    • 데이터 스토에서 적재할 파일을 목록화하는게 가장 느린 상황
  • 해결책
    • 파일을 한번만 목록화 하거나 미리 파일명을 기록하고 목록화는 안하는게 좋음 = manifest pattern
    • 주어진 transaction 내에서 생성된 파일 목록을 메타데이터 위치에 저장된 commit log에 write
    • commit log file은 manifest의 역할을 함
    • manifest file = 데이터에 대해 필요하고 중요한 모든 정보를 제공하는 파일
  • 결과
    • 복잡성
      • 실행 flow가 복ㅈ잡해짐
    • size
      • manifest는 매우 커질수도있음
      • 특히 연속 스트리밍작업의 경우.
      • maximum limit을 구성해야함

8.4 데이터 표현

  • 어떤 속성들이 함께 저장될것인가?
  • 어떤 테이블을 생성할것인가?

정규화기

Normalizer Pattern 디커플링 선호 정보를 중복시키지 않음으로서 일관성 유지에 장점이 있음

  • 문제
    • 불변속성이 반복되어 갱신 연산이 느려지고있음
    • 데이터반복, 느린갱신 문제 해결이 필요
  • 해결책
    • 정보를 한번만 표현하여 반복을 줄이려고함 = 정규화
      1. 비즈니스 엔티티 정의
      2. 비즈니스 엔티티 설명
      3. 비즈니스 엔티티 간의 관계 정의
    • 제1정규형
      • 반복되지 않은 원자적 값을 가짐
      • 기본키로 고유하게 식별
    • 제2정규형
      • 기본키에만 의존
    • 제3졍규형
      • 이행적 의존성이 없음
      • 기본키가 아닌 모든컬럼은 기본키에만 의존
  • 결과
    • 복잡성이 매우 크지만, 일관성 유지를 위해 지불해야하는 대가임
    • 쿼리비용
      • 조인비용이 많이 든다
      • 와노하하기 위해 broadcast mode 사용 가능
    • archive
      • dimension, entity table은 시간에 민감
      • SCD기법으로 완화 가능 (slow changing dimension)

역정규화기

Denormalizer Pattern 조인비용을 완화하기위한 패턴

  • 문제
    • 쿼리실행시간이 지나치게 길어짐
    • 원인은 8개테이블 조인
  • 해결책
    • 쿼리에서 조인을 줄이거나 제거 = 역정규화기 패턴
    • 테이블을 평면화하여 네트워크로 데이터 교환이 필요 없도록함
    • 일반적인 컬럼 or 중첩구조(json, struct)컬럼으로 구성 가능
  • 결과
    • 고비용 갱신
      • 모든 속성이 중복되어
      • 한 레코드 갱신시 여러 레코드를 함께 변경해야함
      • 스냅샷으로 간주하여 갱신을 없애면 완화가능
    • 스토리지
      • 동일정보를 반복저장하므로 공간 낭비가 생김
      • 인코딩기법으로 완화가능
    • 안티패턴
      • 도메인 지향적 로직을 따르지 않으면 안티패턴이 될 수 있음