data7 MIN READ

[데이터 엔지니어링 디자인 패턴] 04. 멱등성

[데이터 엔지니어링 디자인 패턴] 04. 멱등성

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

제거할 수 없는 중복 데이터의 경우, ‘멱등성 디자인 패턴’을 통해 완화할 수 있다.

멱등성(idempotency) = 아무리 호출해도 항상 결과가 같음 ex. absolute 함수 즉 데이터 처리 잡을 여러번 실행해도 매번 중복된 데이터가 생기지 않거나 / 생기더라도 명확히 식별 가능해 출력의 일관성을 확보하는 방법.

4.1 덮어쓰기

  • 데이터 제거 시나리오. = 데이터를 새로 쓰기 전에 기존데이터를 삭제
  • 대용량 데이터셋의경우, 집약된 컴퓨팅 자원 필요

빠른 메타데이터 정리기

Fast Metadata Cleaner 데이터 파일과 상호작용 할 필요가 없어 가장 빠름. 단, 물리적 수준이 아닌 논리적 수준에서 작동. DELETE/INSERT

  • 문제
    • delete/insert로 데이터를 처리
    • 시간이 지날수록 delete 성능이 나빠짐
    • 확장가능하고 멱등성있는 파이프라인 설계 필요
  • 해결책
    • delete = 대용량데이터에서는 성능이 떨어질수있음 (데이터를 식별)
    • 정답은 drop / truncate = 빠른 메타데이터 정리기 패턴의 기반.
    • 데이터셋이 물리적으로 파티션된 여러개의 데이터셋으로 형성된 논리적 단위라면?
    • ⇒ 데이터셋을 여러 테이블에 저장하고 view(단일 추상화)로 한곳에서 보여줄수있음.
    • 즉 데이터셋 파티셔닝과 데이터셋 오케이스테이션에 의존
    • 파티셔닝 = 멱등성의 세분화(idempotency granularity)
    • 파티션 단위 = 테이블 정리를 위해 메타데이터 작업을 적용할 단위
    • 데이터베이스에서 테이블 삭제하기 전에, 뷰에서 테이블 제거로 다운타임 없이 구성
  • 결과
    • 세분화와 백필링 경계
      • 백필시 멱등성 세분화 정의(=파티션)만큼 전부 다시생성해야함
      • 즉 주단위로 파티션한 상태에서 일단위 데이터가 필요해도, 주단위로 다시생성해야함
      • fine-grained backfill이 어려움.
    • 메타데이터 제한
      • 파티션 테이블 무한정 생성은 불가능
      • freezing 단계 추가
      • ex. 최근 52주단위의 테이블만 유지, 이후 freezing
      • object store에서는 구현 힘듬
    • 데이터 노출 계층
      • 엔드유저가 세부노출을 알 필요가없다면?
      • 단일단위로 노출. ⇒ ex. view
    • 스키마 진화
      • 스키마 진화시 스키마 갱신을 위한 별개 파이프라인 필요.

데이터 덮어쓰기

Data Overwrite 메타데이터 연산을 수행할 수 없는 경우라면 데이터 연산을 적용. MERGE / UPSERT

  • 문제
    • 백필링작업이 중복된 레코드를 생성 ⇒ 멱등성 깨짐
    • 그러나, 적절한 메타데이터 계층이 없는상태
  • 해결책
    • data overwrite 패턴에 의존해야함.
    • 구현
      • 데이터 처리 프레임워크를 사용하는 경우, 옵셜설정만 하면 됨 (ex. replaceWhere)
      • SQL을 사용하는 경우,
        • DELETE FROM + INSERT INTO
        • INSERT OVERWRITE
        • LOAD DATA OVERWRITE
    • 덮어쓰기 명령 실행해도, 데이터가 반드시 사라지지는 않음
    • ex. 데이터 스토어가 과거데이터 복원기능을 지원..
  • 결과
    • 데이터 오버헤드
      • 데이터 작업이 포함
      • 파티션되지 않았다면 성능 저하 동반
      • 파티셔닝을 통해 replace작업 성능을 올릴수있음
    • vacuum 필요
      • 디스크에 여전히 예전데이터 있을수있으므로
      • 죽은레코드 공간 회수를 위해 vacuum을 실행해야함

4.2 갱신

  • 데이터셋을 완전히 삭제 = idempotency한 쉬운방법
  • 몇 데이터셋은 완전한 대체에 적합하지음. ex. 증분형 데이터셋
  • 각 entity의 최신 버전만 유지하기 위한 작업이 필요

병합기

Merge 패턴 데이터셋이 정적이고 갱신/삽입만 지원한다면 변경사항을 병합하는것이 최선의 방법.

  • 문제
    • cdc로 동기화된 변경사항 스트림 관리 파이프라인 작성
    • delta lake table로 저장된 변경사항을 전부 복제해야함
    • 특정 시점에 존재하는 데이터를 완벽히 반영해야함
    • 중복을 포함해서는 안됨
  • 해결책
    • 새 데이터셋과 기존 데이터셋을 결합하기 위한 속성을 정의
    • 처리계층에서 데이터셋을 결합할 방법 정의
      • 보통 Merge (=Upsert) 명령어 사용
    • 병합기패턴은 삭제를 지원하지 않기때문에, 보통 변화감지후 물리삭제나 논리삭제를 적용
  • 결과
    • 고유함
      • 레코드 식별을 위한 불변의 속성 정의가 필요
      • 이부분이 미흡하면 백필링시 중복발생 가능
    • 입출력
      • 데이터기반 패턴이라 컴퓨팅 집약적.
      • 영향받은 레포트를 먼저 검색해 조회를 최적화해야함.
      • 관련없는 파일 처리를 pass해야함
    • 백필링을 사용한 증분 데이터셋
      • 증분하는 형식이기때문에 백필링을 중간부터하면 일관성이 깨질수있음
      • 첫번째 리플레이된 실행으로 롤백하는 복원 메커니즘을 적용해야함

상태 저장 병합기

Stateful Merger

  • 문제
    • 병합기패턴 사용하다가, 데이터셋에서 문제 발생
    • 데이터셋 백필시 일관성 유지가 중요한 상태
    • 마지막의 유효한 버전으로 복원 가능해야함
  • 해결책
    • 시작부분에 병합된 테이블을 불러오고,
    • 병합문을 실행하고
    • 마지막에 상태테이블을 갱신함.
    • 백필링모드에서만 복원 과정이 일어남.
  • 결과
    • 버전관리되는 데이터 스토어
      • 데이터스토어의 버전관리가 이루어져야함
      • 버전관리기능이 없는 db는 직접 구현해야함
      • 실행시간을 통해 기준점보다 미래 레코드는 모두 지움
    • vacuum 작업
      • 버전관리 데이터셋은 상태테이블 구현이 쉽지만
      • 설정된 보존기간이 지나면 오래된 버전은 순차적으로 삭제되므로 유의해야함
      • 보존기간이 넘으면 backfill은 불가피함
    • 메타데이터 작업
      • data compaction은 새 버전의 테이블을 만듬.
      • 이때문에 놓치는 작업이 생길 수 있음
      • 컴팩션으로 버전이 증가한다고 가정하고, 이전버전을 사용해야함

4.3 데이터베이스

  • 이전 패턴들은 데이터 추가작업이 필요
  • 이 작업이 부담스러우면 멱등성을 보장하는 DB에 의존하면 쉬워짐

키 기반 멱등성

Keyed Idempotency 키 기반 데이터 스토어와 멱등성 키 생성 전략을 이용

  • 문제
    • 방문이벤트를 처리하는 사용자 세션을 생성
    • 태스크가 재시도될경우 중복데이터가 생기지 않도록 멱등성을 가져야함
  • 해결책
    • 멱등성 = 데이터 처리측의 키 생성 로직에 적용
    • 방문이벤트가 모두에 동일한 세션ID가 생성되어 한번만 기록되어야함
    • 사용자ID + 첫 방문시간 조합하면 멱등성 키 생성이 간가능
    • 이때 “이벤트 시간 속성”은 변경이 가능하므로. append time(= approximate arrival timestamp)같은 시간을 사용하는것이 적합.
    • 데이터가 좀 늦게 도착해도 키의 일관성 유지 가능.
  • 결과
    • 데이터베이스 의존성
      • 관계형 데이터베이스의 경우 insert로 중복데이터 삽입시 오류발생가능
      • insert 대신 merge 해야함. (=merge패턴처럼 복잡해짐)
      • 카프카의경우는 compaction 메커니즘때문에 일정기간 중복엔트리를 볼수있음
    • 변경 가능한 데이터 원천
      • 컴팩션으로 인한 이슈
      • 오래된 이벤트가 제거됨
      • 키생성에 사용된 첫번째 이벤트가 삭제될경우 멱등성 보장이 깨지게됨
      • ⇒ 다른키를 사용하는게 합리적

트랜잭션 기반 작성자

Transactional Writer 트랜잭션은 멱등성 데이터 프로듀서를 구현하는데 도움이 되는 강력한 db기능 all-or-nothing의미론 제공.

  • 문제
    • 클러스터에서 노드 제거시 태스크가 재실행될수있음
    • 재시도되면서 중복된 데이터와 불완전한 레코드를 사용자에게 노출할수잇음
    • 잡이 불안젆란 데이터를 노출하지않도록 보장해야함
  • 해결책
    • 프로듀서는 트랜잭션을 초기화
      • START TRANSACTION
      • BEGIN …
    • 초기화 이후 데이터 기록
    • 기록 완료 후 commit or rollback
    • 멱등성은 all-or-nothing transaction semantic에서 비롯됨
    • 오류가잇을경우 고아레코드가 생성될수도 있음 ⇒ 백필시 또 삽입될수도..
    • 멱등성은 현재 실행에 대해서만 보장됨
    • 격리수준이 read uncommitted면 불완전한 데이터 노출될수도잇음
    • 트랜잭션을 지원하는 db들이 분산데이터 처리도구와 완벽하게 통합되지는 않음
  • 결과
    • 커밋단계
      • 여는단계 / 커밋하는 두단계가 추가됨
      • 커밋로그파일 생성시에만 데이터는 가시성을 갖추게됨
    • 분산처리
      • 트랜잭션지원은 글로벌하지않음
    • 멱등성 범위
      • 트랜잭션 자체에 한정됨
      • 백필링에서도 마찬가지..

4.4 불변 데이터셋

  • 기존 패턴은 데이터셋을 원하는 방식으로 변경할 수 있음
  • 기존 데이터를 삭제하거나 갱신할 수 없다면? ⇒ 간접수준 도입 필요

프록시

Proxy 추가적인 간접 수준을 도입하여, 어떠한 문제든 해결할 수 있다

  • 문제
    • 잡이 매번 전체데이터셋을 생성함
    • 법무팀에서 과거 버전의 복사본을 모두 저장하는것을 요청
    • 각 복사본은 유지하되, 한곳에서만 최신테이블 노출하게해야함
  • 해결책
    • 프록시 = 엔드사용자와 실제 물리적 스토리지 사이의 중간 컴포넌트
    • 타임스탬프 / 혹은 버전테이블 사용
    • 생성 후 쓰기권한 제거 → 테이블은 반드시 한번만 기록됨
    • WROM(write once read many) 방식으로 제어하기도함
    • 단일 데이터 접근지점 (=proxy) 생성
    • 대부분 passthrough view 로 구현
    • 혹은 해당 뷰가 없으면, 직접 구현
  • 결과
    • 데이터베이스 지원
      • 뷰 기능이 없으면 직접 구현
      • 조회가정이 번거로워질수도..
    • 불변성 결정
      • 태스크의 출력을 설정하여 불변성 적용
      • 잠금 / 쓰기권한 제거 필요