[데이터 엔지니어링 디자인 패턴] 06. 데이터 흐름
[데이터 엔지니어링 디자인 패턴] 06. 데이터 흐름
데이터 엔지니어링 디자인 패턴 시리즈의 글입니다.
데이터셋 생성에 필요한 모든 파이프라인을 설계, 조정해보자
데이터 흐름을 디자인함으로써 데이터로 더 많은 혜택을 창출할 수 있다
6.1 시퀀스
- 순서 = 파이프라인의 복잡성, 성능, 유지보수에 영향을 미치는 중요한 요소.
로컬 시퀀서
Local Sequencer pattern 로컬, 즉 동일한 pipeline / job 내에서 조정하는 방법.
- 문제
- 실행 실패가 잦아진 레거시 잡을 개선하려고함
- 비즈니스로직은 그대로 유지되어야함
- 해결책
- 가장 쉬운방법은 비즈니스로직을 작은단위로 분해하는것.
- 하나의 컴포넌트를 작은 여러 연결된 항목으로 분리하여 순차적으로 실행
- 태스크간 의존성은 데이터셋 의존성에 맞게 구성
- 데이터 오케스트레이션 기반 / 데이터 처리계층 기반 모두에 구현 가능
- 아래 세 가지 기준에 따라 구현 레이어 선택
- 관심사의 분리
- 유지보수성
- 구현을 위한 노력
- 결과
- 경계
- 경계를 잘못 설정하면 latency가 길어지거나 다른 파이프라인에 영향을 줄 수 있음
- 재시작 경계 (즉, 개별적으로 재시작 니즈가 있는 구간이 어딘지?) 를 고려해야함
- 컴퓨팅 비용이 필요한 작업 사이에 경계를 설정하기도함
- 트랜잭션 관점에서 로직 분리를 할 수도 있음
- 경계
독립된 시퀀서
Isolated Sequencer Pattern 보통 독립된 여러 워크플로우가 서로 협력하여 최종 인사이트를 생성하는 더 복잡하고 커다란 워크플로우의 일부가됨.
- 문제
- 팀에서 raw dataset을 정리, 강화하여 다양한 뷰로 제공하는중
- 데이터 시각화팀에서는 해당 데이터를 변환하는 작업을 추가로 하려고함.
- 해결책
- raw data의 정리/강화 파이프라인과 데이터 변환 파이프라인을 단일 프로세스로 병합 불가능 (조직이 다름)
- 물리적으로 독립된 파이프라인을 결합할 방법이 필요
- 컨텍스트 경계를 먼저 정의
- ex. producer / consumer
- 그러나 데이터 producer면서 동시에 consumer 가 되는 상황도 있음
- 접근방식에 따라 로직을 여러 파이프라인으로 나누는 방안 고려
- 둘을 함께 유지할 수도 있음
- trigger machanism을 정의
- 데이터 기반 전략 : 준비마커패턴 사용. 컨슈머는 파일을 센싱하여 작업 시작
- 작업 기반 전략 : 프로듀서가 직접 컨슈머 잡을 트리거.
- 결과
- 모든 파이프라인을 동기화상태로 유지해야함
- 독립성을 추가함으로써 별도의 운영 제약이 추가됨
- 스케쥴링
- 태스크기반 해결책 - 프로듀서가 컨슈머를 트리거링하기위해 같은 스케쥴러를 공유하거나 더 복잡한 구조를 도입해야함.
- 프로듀서는 trigger skip condition정의 필요
- 컨슈머는 프로듀서일정에 맞춰 자신의 일정을 조정해야함
- 소통
- 여러팀에서 파이프라인을 관리 ⇒ 조직에 효과적인 소통문화 필요
6.2 팬인
- 시퀀스는 각 단계가 특정 순서를 따라 진행됨
- 보통의 파이프라인은 branch가 생성되기도 하고, 다시 merge되기도 함
정렬된 팬인
Aligned Fan-in Pattern 부모태스크가 성공해야 모든 하위 태스크가 계속 진행할 수 있음 느슨한 결합으로 파이프라인을 구성.
- 문제
- 방문이벤트는 시간별로 분할됨
- 컨슈머는 전체 view에만 관심이 있음
- 해결책
- 태스크간 의존성이 존재
- 의존성을 데이터 오케스트레이션 계층 or 데이터 처리계층에서 해결 가능
- 오케스트레이션계층 구현
- 별도의 브랜치를 정의하고 공통 태스크로 병합
- ex. 각 시간에 대한 부분집계 생성 → 모든 부분집계 완료 후 최종 view 계산
- 데이터처리계층
- 간단하지않음
- 브랜치를 정의하고 브랜치들이 어떻게 상호 작용할지 정의 필요
- UNION (수직적 정렬) or JOIN (수평적 정렬) 사용
- feedback loop 최적화라는 장점 존재. (오류나도 빨리알수있음)
- 특정 시간이 실패할경우, 해당 시간만 수정하고 리플레이하면됨.
- 결과
- 인프라 스파이크
- 탄력적인 프로비저닝 필요
- 프로비저닝이 어렵다면 적절한 균형점 찾는것이 중요
- 스케줄링 스큐
- 부모실행시간이 균형적이지 않으면 scheduling skew 발생
- 성공한 태스크 여럿이 지연된 태스크 하나를 기다리게됨
- 스케쥴링 오버헤드
- 파이프라인 세분화가 과도하면 스케쥴링 오버헤드를 수반
- 오케스트레이터는 대부분의 자원을 스케줄링 조정에 할당
- 느슨한 결합 / 높은 가독성에서 감수해야하는 대가
- 복잡성
- 결합을 느슨하게 하기위해 분리할수록 파이프라인이 길어짐
- ⇒ 가독성과 이해도가 낮아져 부정적 효과를 초래하기도함
- 결국 적절한 경계를 찾아야.. (trade-off)
- 인프라 스파이크
비정렬 팬인
Unaligned Fan-in Pattern 때때로 모든 부모가 성공해야한다는 조건은 latency를 늘리고, 잘못된 semantic을 초래
- 문제
- Aligned Fan-in Pattern으로 구현한 파이프라인에서, 실패한 태스크를 관리할 적절한 메소드가 부족
- 회의에서 일부 데이터셋이라도 공개하고, 나중에 빈 부분을 채우자고 합의됨
- 해결책
- 비정렬 팬인 패턴을 사용하면 일부 부모가 성공하지 못해도 자식 태스크 실행이 가능
- 모든 부모가 실패하면 실패 기준에 따라 fallback or 오류 관리 작업을 트리거할 수 있음
- 오케스트레이션 도구에서 trigger condition을 설정해야함
- 결과
- 팬인 패턴과 동일한 단점을 가짐
- 가독성
- 데이터 흐름에대한 가독성과 이해도를 감소시킬 수 있음
- 코드를 파악해야만 실행 흐름을 파악할 수 있음
- 파이프라인이 혼란스러워짐
- 부분 데이터
- 컨슈머에게 부분성공에대해 알리는것이 중요함
- 이게 실패하면, 컨슈머는 완전성 상태에 대해 잘못된 추정을 하게됨
- 메타데이터 계층에 추가하거나
- 다운스트림 컨슈머에 알림을 하거나 등..
6.3 팬아웃
- 한 태스크가 다른 태스크의 입력이 되는 경우
- 한 데이터셋이 데이터분석팀이나 데이터 사이언스팀 등 여러팀에 다양한 목적으로 사용되는 경우
병렬 분할
Parallel Split Pattern 하나의 부모태스크에 최소 두개이상의 자식이 있는 경우 ⇒ 자식태스크들은 독립적으로 분리되므로, 병렬실행이 가능
- 문제
- 레거시시스템을 마이그레이션하려고함
- 기존 시스템을 유지시키면서, 새 시스템들 가동함
- 데이터는 양쪽 시스템에 dual write해야하는 상황
- 해결책
- 작업을 병렬 부분으로 나누고, 동시에 실행함
- 데이터 오케스트레이션 계층에서 쉽게 구현 가능 (API사용)
- 데이처 처리 계층에서는 구현이 간단하진않음
- 분할처리가 별개의 데이터 조회 작업을 하면 안됨
- 일반적인 계산이 한번만 실행되어야함
- 보통 중간 데이터셋을 구체화하여 사용
- 계산 실행 시간에 민감하다면 전용자원 or 오토스케일링을 통해 병렬 분할 작업을 수행
- 결과
- 차단된 실행
- 분할해 실행한 작업을 다시 조인해야하는경우
- 각 파이프라인은 가장 느린 브랜치가 완료될때까지 기다려야함
- ⇒ 느린 브랜치 내보내기 등으로 해결해야함
- 하드웨어
- 데이터 처리계층의 경우, 중간데이터셋을 사용하는 자식 태스크들은 동일한 환경에서 실행되어야하기때문에 하드웨어 요구사항이 동일해야함
- 잡을 나누고 각각 전용 하드웨어에서 병렬잡을 실행하여 완화할수있음
- 차단된 실행
배타적 선택
Exclusive Choice Pattern 공통 부모에 의존하지만 병렬 다운스트림 태스크를 실행하는 대신, 하나만 선택함 (XOR Split)
- 문제
- 병렬 분할 패턴으로 수행한 마이그레이션 이후, 백필링이 필요해짐
- 파이프라인을 새로 생성하지않고 백필링을 하려면?
- 해결책
- 자식태스크가 여러개지만 하나만 실행해야하는경우 = 배타적 선택 패턴
- 어떤 경로를 따를지 조건 평가 작업을 추가
- 보통 오케스트레이션 프레임워크는 branch operator를 제공
- 데이터 처리계층에서도 아래 구문들로 구현 가능
- if-else
- switch
- 결과
- 복잡성 양산 공장
- if-else 지옥..
- 숨겨진 로직
- 잡에 조건문이 생기기때문에, 다른 데이터스토어와 상호작용하는경우 문제가 생김
- 데이터 오케스트레이션 계층 위에 패턴을 적용하는게 좋을수도.
- 무거운 조건
- 데이터 처리계층에 패턴을 구현한다면, 잡의 실행시간에 영향을 미침
- 복잡성 양산 공장
6.4 오케스트레이션
- 데이터 오케스트레이션 계층에 위치한 정적자원의 흐름
- 데이터 처리 태스크를 수행하는 동적 컴포넌트의 흐름
단일 실행기
Single Runner Pattern 선언된 파이프라인을 단일로 실행
- 문제
- 증분 세션화 처리기 패턴으로 세션화 파이프라인 구현
- 오케스트레이션 작업이 필요한 상태
- 해결책
- 실행기가 필요
- 증분적이므로 순차실행을 포함
- 단일 실행기 = 동시성 수준을 1로 설정하여, 항상 단일로 실행을 보장
- 결과
- 백필링
- 재처리시간이 느려짐
- 파이프라인 전부를 백필할 필요가 있는지 살펴보고, 일부만 처리하도록해야..
- 지연
- 데이터가 점점 지연되면, 모든 다운스트림 컨슈머가 추가지연으로 고통받음
- 확장성있는 인프라에서 실행해서 완화시켜야함
- 백필링
동시 실행기
Concurrent Runner Pattern 선언된 파이프라인을 동시에 실행
- 문제
- 외부의 정적인 상태의 데이터를 가능한 빨리 내부 DB로 가져오고자함
- 순차 실행은 필요하지 않은 상태
- 해결책
- 서로 독립적이고 동시성 제약이 느슨하다면, 동시실행기 패턴 사용
- 동시성을 1보다 높게 정의
- with great power comes great responsebility
- 현재 실행중인 인스턴스가 허용된 동시성 수준까지 동시실행
- 결과
- 자원부족
- 멀티테넌트 환경이면 더욱 영향이 큼
- 워크로드 관리 기능으로 동시성을 제어
- 공유 상태
- 동시실행에서의 가장 흔한 함정
- 비결정적 실행은 예기치않은 부작용을 생성
- 중복 트리거 or 일부만 트리거 하는 부작용이 생길수도..
- 자원부족