data7 MIN READ

[데이터 엔지니어링 디자인 패턴] 03. 오류 관리

[데이터 엔지니어링 디자인 패턴] 03. 오류 관리

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

이 세상에 오류와 데이터 품질 문제 외에 확실한 것은 아무것도 없습니다

데이터는 동적이어서 우리가 기대하는 데이터의 모습이 life cycle동안 그대로 유지되지 않는다 신뢰할수없는 네트워크로 데이터가 늦거나, 일시적인 충돌로 재시도하여 데이터가 중복되는 등 소프트웨어 엔지니어링 문제를 데이터는 그대로 답습한다.

3.1 처리할 수 없는 레코드

unprocessable records는 자주 치명적인 장애를 일으며 job을 중단시킴 항상 fail-fast 방식이 가능하지않음

데드 레터

쉬운방법은 잘못된 레코드를 무시하는것이지만, 그게 불가능하다면 잘못된 레코드를 다른곳에 저장하여 추가 조사를 수행하여야함

  • 문제
    • producer가 unprocessable record를 생성하기 시작
    • 레코드가 실패해도 파이프라인이 계속 작동하며,
    • 오류를 나중에 조사할 기회도 재공해야함
  • 해결책
    • dead-letter pattern
    • 잡이 실패할 수 잇는 코드 위치를 식별하고 안전제어를 추가
    • 거기에 해당하는 output (=dead-letter) 을 구성
    • 가용성이 높고 빠르고 모니터링하기 쉬운 저장소(ex. object store)에 저장
    • 실패한 record를 replay-pipline으로 오류처리 완료
    • 배치 / 스트리밍 모두에서도 사용 가능
  • 결과
    • 매일의 유지보수 작업에는 유리
    • 오류를 무시하면 부작용 존재
      • 스노우볼 백필링 : 백필링시 모든 down-stream 컨슈머에서 동일한 프로세스가 트리거되는 효과
      • 데드 레터 레코드 식별 : 메인스토어에 통합해서 flag로 구분하거나.. 메타데이터를 활용 가능
      • 순서와 일관성 : 데이터 일관성이 깨질 수 있음
      • 오류-안전 함수 : 예외없이 null로 반환하기때문에 데드레터 패턴 구현이 어려워짐
      • 오류 or 실패 : 오류/실패를 은폐하게될수 있으므로 알맞은 경고 계층을 두어야함

3.2 중복된 레코드

분산시스템에서 exactly-once를 보장하는것은 매우 어려움

윈도우 중복 제거

중복제거의 핵심은 데이터를 제한하는것.

  • 문제
    • 자동재시도때문에 스트리밍계층에 중복 이벤트가 자주 발생
  • 해결책
    • 윈도우 중복제거 패턴을 사용
    • 각 레코드의 고유성을 보장하는 중복 제거 속성(unique key)를 식별
    • 중복 제거 범위를 설정
      • batch : 현재 처리중인 데이터셋
      • streaming : 시간기반 window
    • 구현
      • batch : distinict / window함수사용
      • straming : state store와 상호작용 필요 (처리되었는지 저장해야함)
  • 결과
    • 완벽한 중복제거를 보장하지는 못함…
    • 공간 vs 시간 trade-off : 윈도우 크기를 줄이면 자원은 작지만 데이터를 놓칠수있음..
    • 멱등성 producer : 완벽히 보장이 안되기때문에 결국에는 멱등성 패턴을 적용해야함

3.3 지연 데이터

데이터 처리 파이프라인에 매우 심각한 영향을 미침

지연 데이터 탐지기

  • 문제
    • 때때로 네트워크 연결을 놓치고,
    • 연결이 복구되면 뒤늦게 이벤트를 발송하게됨
  • 해결책
    • late data detector 패턴으로 감지
    • 시간기반 속성 정의 필요 - 이벤트 발생 시점
    • 각 파티션에서 적용할 지연 집계 전략을 정의
      • 전략은 monotonic increase 해야함
      • 일반적으로 max(파티션에서 가장 큰 이벤트시간)을 기준으로함
    • 모든 파티션에 대한 단일 이벤트 시간을 계산할 추가집계전략 결정
      • global event time에는 min / max를 여러수준에서 결합하여 사용
    • 허용된 지연 시간 속성이 필요
      • MAX (event time) - allowed lateness = water mark
      • 이벤트를 제시간에 도착한것으로 간주하는 최소 이벤트시간
    • 이벤트 지연 감지 후
      • 가장간단한 방법 = 무시하기
      • 가치있다면 = (지연 데이터 통합기 패턴) 따로 시스템에 기록
  • 결과
    • 지연 데이터 캡쳐 : 프레임워크들이 지원안할수있음
    • min전략 : 무한반복 / 과거에 얽매일수 있음.
    • max전략 : 편향된환경에서는 지나치게 공격적으로 작동하여 많은 레코드를 누락할수있음.

정적 지연 데이터 통합기

지연데이터가 가치있고 데이터셋에서 높은 비율을 차지한다면 이들을 잃는것은 바람직하지않음

  • 문제
    • 15일간 근사치로 통계를 내야함
    • 15일보다 오래되지 않은 지연데이터는 무시
    • 따로 지연데이터 보정 파이프라인을 둠
  • 해결책
    • static late data integrator 패턴 사용
    • static lookback window (지연데이터를 위해 얼마나 과거로 돌아가야하는가?) 를 정의
    • 지연 데이터 통합 프로세스를 배치
      • 통합 → 실행
      • 실행 → 통합
      • 통합 / 실행 (병렬)
      • 전략은 상황에 맞게 선택
  • 결과
    • 복잡성 비용이 증가하게됨
    • 스노우복 백필링 효과 (지연데이터 있는 모든 파티션 replay)
    • 중첩실행 및 백필링: lookback window 지속시간을 고려해야함
    • 파이프라인 트리거 : 백필링은 메인파이프라인의 일부가 되어야함.
    • 자원 낭비 : 지연데이터 포함 안할수도 있는데 트리거링해야함.
    • 시간 요구 사항 : 데이터셋에 시간개념이 없으면 지연데이터 감지/통합 어려움.

동적 지연 데이터 통합기

지연데이터의 영향을 받는 파티션만 적재하는 동적인 접근방식이 필요

  • 문제
    • 초기15일 윈도 이후의 데이터까지 아울러 지연 데이터 모두를 통계내고싶은 상황
  • 해결책
    • 동적인 백필 윈도우를 사용 = 백필된 모든 파티션이 실제로 지연데이터를 포함
    • 이를 위해 각 파티션의 마지막 갱신 시간을 저장할 추가 데이터구조가 필요
    • 해당 데이터를 기반으로 백필할 파티션을 얻음
    • 일반/백필 모두 데이터 처리 후 마지막 처리 시간을 갱신해야함
  • 결과
    • 자원낭비 문제 해결
    • 룩백윈도우 조정
    • 동시성
      • 한 파티션이 여러번 실행될수잇음
      • 방지하려면 상태 컬럼 추가해야함. (is_processed)
      • 처리하기 전/후로 is_processed 컬럼 갱신해줘야함
    • 상태 저장 파이프라인과 매우 지연된 데이터
      • 매우 지연된 레코드를 받을때 과도 한 백필을 초래할수잇음
      • 결국 동적으로 생성된 룩백 우니도에 대해서도 허용되는 룩백 윈도를 정의해야함
    • 스케쥴링 복잡성
      • 경우에따라 파티션의 마지막 수정시간을 구하는게 어려울수있음
      • 직접 추적테이블을 구현해야할수있음

3.4 필터링

오류의 발생 ≠ 기술의 실패 필터 구현 실수로 end user에게 부분적인 데이터 or 불량 데이터가 노출될 수 있음

필터 인터셉터

필터링을 통해 주어진 비즈니스 사용 사례에 관한 레코드만 선택 가능 매우 중요한데도, 필터링 조건을 간과하는 경우가 많음 과도한 조건 / 버그 필터링 오류를 감지하가 필요하다.

  • 문제
    • 새 배포 후 필터링 데이터가 급증
    • 실행계획으로는 어디가 문제인지 알수 없는 상황
    • 필터링 표현식을 단일 표현식으로 통합하고자 함
  • 해결책
    • 본래 물리적 쿼리 실행 계획 분석으로 해결
    • 다만 엔진이 하나의 실행단계로 결합하는 최적화시 정밀성이 떨어질 수 있음
    • filter interceptor 패턴으로 해결 가능
    • 단순히 필터링 조건 표현하는 대신 조건이 참으로 평가되면 카운터를 증가시키는 로직으로 필터링 조건을 감싸야함
    • sql같은 선언적 언어에서는 서브쿼리나 임시테이블 사용
    • 유효성 결과를 저장하는 새 컬럼을 포함 → 차후 메인쿼리 필터링 술어로 사용
  • 결과
    • 런타임 영향 : 필터링 조건을 wrapper로 감싸는건 실행시간과 자원에 영향을 미침. (특히 임시테이블 만드는 경우)
    • 선언적 언어 : 번거로우므로 가끔은 프로그래밍 api로 구현하는게 나을수도있음
    • 스트리밍 : 비저장 잡을 상태저장 잡으로 변환해야하고, 인터셉터 통계를 위한 시간 경계를 정의해야함. 필터링 통계는 시간기반 처리 윈도에 의존하고, 이후 전체이력을 단일뷰로 제공.

3.5 내결함성

스트리밍같은 연속적인 데이터 처리 워크플로의 복구가능성을 보장하는 일종의 보호기능. 잡을 중단한 후 언제 시작해야하는가? ⇒ 적절한 진행사항 추적 메커니즘이 없으면 데이터를 중복처리하게 될 수 있음.

체크포인터

  • 문제
    • 누적 고유방문수 카운팅을 구현하려고함
    • 치명적 실패로 잡이 중단되고 데이터를 처음부터 다시 처리해야하는 상황이 걱정임
    • 위험을 줄이기 위해 쿼리가 진행되면서 결과를 지속 저장하고싶음
  • 해결책
    • 잡은 소비된 데이터 원천에서 최신위치와 계산된 상태를 추적해야함
    • = checkpointer 패턴이 이러한 추적 매커니즘을 구현
    • checkpointing은 persistent 저장소에 데이터 처리 프로세스를 기록
      • 데이터 처리 프레임워크 기반 : ex. spark, flink 들은 진형경과 추적관리기능을 갖춘 복원력 있는 객체스토어에 진행경과 메타데이터를 저장함
      • 데이터 스토어 기반 : data store SDK 사용하는 경우 data store와 상호작용 가능. ex. 아파치 카프카 sdk는 토픽에 저장. AWS 키네시스는 dynamo db에 저장
    • 구현
      • 구성기반 방식 : 체크포인트 저장 빈도만 설정하고 실행은 라이브러리에 위임
      • 코드 기반 방식 : 코드상의 의도적 체크포인팅 작업에 의존.
  • 결과
    • 내결함성(fault tolerance)매커니즘을 제공하지만 데이터지연이라는 단점이 있음
    • 전송보장 vs 지연시간 trade-off : 체크포인팅 빈도가 높아지면 이로인한 오버헤드로 잡이 느려짐
    • 정확히 한 번만 처리된 것같은 느낌 : 분산시스템에서 excatly-once는 없음.. 멱등성 패턴을 적용해야함