워크플로 관리
기업 내의 신청, 승인, 보고 등의 정형적인 업무 프로세스와 같이 정해진 업무를 원할하게 진행하기 위한 구조를 일반적으로 워크플로 관리라고 합니다.
태스크는 정해진 스케줄에 따라 자동으로 실행되고, 무언가 비정상적인 일이 발생한 경우에는 사람이 개입하여 문제를 해결합니다.
워크플로 관리 도구
워크플로 관리 도구의 주요 역할은 정기적으로 태스크를 실행하고 비정상적인 상태를 감지하여 그것에 대해 해결을 돕는 것입니다.
워크플로 관리 도구는 주로 다음과 같은 기능을 제공합니다
- 태스크를 정기적인 스케줄로 실행하고 그 결과 통지
- 태스크 간의 의존 관계를 정하고 정해진 순서대로 빠짐없이 실행
- 태스크의 실행 결과를 보관하고 오류 발생 시에는 재실행
워크플로 관리 도구는 크게 두 종류가 있습니다.
하나는 선언형 도구입니다.
선언형 도구는 XML이나 YAML 등의 서식으로 워크플로를 기술하는 타입입니다.
선언형 도구에서는 미리 제공된 기능만 이용할 수 있는데, 그 범위 안이라면 최소한의 기술로 태스크를 정의할 수 있는 특징이 있습니다.
누가 작성해도 동일한 워크플로가 되기 때문에 유지 보수성이 높아집니다.
동일 쿼리를 바꾸어 여러번 실행하거나,워크플로를 단순 반복적으로 자동 생성하는 경우에도 선언형 도구가 사용됩니다.
오픈 소스로 Azkaban, Digdag, Oozie 등이 있습니다.
다른 하나는 스트립트형 도구입니다.
스트립트형 도구는 스트립트 언어로 워크플로를 정의하는 유형입니다.
스크립트형 도구는 일반적인 스크립트와 동일하게 변수나 제어 구문을 사용할 수 있어서 태스크의 정의를 프로그래밍할 수 있습니다.
스크립트 언어에 의해 데이터 처리를 태스크 안에서 실행하는 것도 가능합니다.
예를 들어 파일의 문자코드를 변환하면서 서버에 업로드하는 식의 태스크는 스트립트형 도구의 강점입니다.
오픈 소스로 Airflow, Luigi 등이 있습니다.
ETL 프로세스에는 스크립트형 도구, SQL의 실행에는 선언형 도구를 쓰는 것도 하나의 방법입니다.
오류로부터의 복구 방법
데이터 파이프라인을 매일 동작시키다보면 다양한 오류가 발생합니다.
오류가 일시적인 장애든지 구현상의 버그든지 신속하게 문제를 해결하여 태스크를 재실행해야 합니다.
워크플로 관리 도구에 의해 실행되는 일련의 태스크를 플로우라고 합니다.
각 플로우에는 실행 시에 고정 파라미터가 부여되어 있습니다.
즉, 플로우에 같은 파라미터를 넘기면 같은 태스크를 실행하게 됩니다.
이렇게 하는 이유는 플로우가 도중에 실패해도 나중에 같은 파라미터로 재실행할 수 있기 때문입니다.
이것이 복구의 기초입니다.
대부분의 워크플로 관리 도구는 과거에 실행한 플로우와 그 파라미터를 자동으로 데이터베이스에 기록하게 되어 있습니다.
그래서 실패한 플로우를 선택하여 재실행하는 것으로 복구를 하게 됩니다.
원자성 조작과 멱등한 조작
복구를 하기위해서는 재실행의 안정성이 필요합니다.
태스크가 도중에 실패했을 때 그 도중 경과가 사라지지 않고 남아있으면 태스크의 재실행에 의해 데이터가 혼재하는 문제가 발생합니다.
그래서 각 태스크는 원칙적으로 마지막까지 성공하거나 실패하면 아무것도 남지 않아야 합니다.
재실행의 안정성을 높이는 방법에는 원자성 조작과 멱등한 조작이 있습니다.
원자성 조작
트랜잭션 처리에 대응한 데이터베이스라면 여러번의 트랜잭션이 한번의 쓰기로 실행할 수 있지만, 그럴 수 없다면 쓰기가 필요한 만큼 태스크를 나눠야 합니다.
이를 일반적으로 원자성 조작이라고 합니다.
하지만 원자성 조작도 문제를 일으킬 가능성이 있습니다.
태스크 구현상의 버그 등으로 원자성 조작 직후에 문제가 발생하면 원자성 조작 자체는 성공하고 있어도 워크플로 관리 도구는 그것을 오류로 여기는 경우가 있습니다.
예를 들어, 데이터베이스에 쓰는 태스크가 있다고 하고 네트워크 경유로 쓰기 명령을 발행한 직후에 통신이 끊겼다고 합시다.
이 경우에는 원자성 조작에 성공하였지만, 데이터베이스에 쓰였는지는 데이터베이스를 봐야 알 수 있습니다.
만약 데이터베이스에 쓰였는데, 워크플로 관리 도구가 오류로 인식하여 재실행하게 되면 중복이 일어나게 됩니다.
이러한 가능성도 허가하지 않을 때는 원자성 조작에 의존한 플로우를 만들면 안됩니다.
적어도 워크플로 관리 도구에 의한 자동적인 재시도는 피하고, 오류의 내용을 반드시 확인한 뒤에 수동으로 복구해야 합니다.
멱등한 조작
더욱 확실한 방법은 동일한 태스크를 여러번 실행해도 동일한 결과가 되도록 하는 것입니다.
이것을 멱등한 조작이라고 합니다.
예를 들어, SQL에서 테이블을 삭제한 후에 다시 만드는 방법 즉, 치환하는 태스크라면 아무리 재실행해도 같은 결과가 나오므로 중복이 발생하지 않습니다.
하지만 현실에서는 항상 멱등한 태스크를 구현할 수 없습니다.
예를 들어, 크기가 큰 기존 테이블에 데이터를 추가하고 싶을 때 과거의 모든 데이터들을 치환하는 것으로 멱등하게 만든다면 부하가 커지게 됩니다.
이러한 경우에는 멱등한 추가와 원자성을 지닌 추가가 있습니다.
멱등한 추가는 테이블 파티셔닝을 이용하여 기존 테이블을 파티션으로 나누고 파티션 단위로 치환하는 것입니다.
원자성을 지닌 추가는 중간 테이블을 멱등하게 만든 후 마지막에 기존 테이블에 추가하는 것입니다.
데이터 파이프라인을 안정적으로 운용하기 위해서는 거기에 포함된 태스크나 플로우를 가능한 한 멱등으로 해야 합니다.
성능상의 이유 등으로 치환이 아닌 추가를 해야할 경우도 있기 때문에 전부 멱등으로 하는 것은 필수가 아닙니다.
최종적으로 워크플로가 안정적으로 실행되고 있는 한, 태스크가 멱등이지 않아도 동작에 지장은 없습니다.
추가가 문제가 되는 것은 중복 뿐이므로, 그것만 주의하면 일반적은 운용으로 문제 될 일은 없습니다.
자원 소비량 컨트롤
워크플로 관리 도구에서 요구되는 다른 하나의 커다란 역할은 외부 시스템의 부하 컨트롤입니다.
태스크의 크기나 동시 실행 수를 변화시켜서 자원의 소비량을 조정하여 모든 태스크가 원할하게 실행되도록 합니다.
너무 대량의 태스크를 동시 실행하지 못하게 제한하는 구조를 잡큐 또는 태스크 큐라고 합니다.
워크플로에 등록하는 모든 태스크는 너무 크지도 작지도 않도록 적절히 나눔으로써 높은 효율로 실행할 수 있고 오류 발생 시의 영향 또한 작게 억제할 수 있습니다.
배치형 데이터 플로우
기술적인 발전에 따라 현재는 다단계의 데이터 처리를 그대로 분산 시스템의 내부에서 실행할 수 있게 됐습니다.
이것을 데이터 플로우라고 합니다.
현재는 MapReduce를 대신할 프레임워크들이 있습니다.
이 프레임워크들에 공통으로 들어가는 것이 DAG 데이터 구조입니다.
DAG
DAG는 수학과 컴퓨터 알고리즘에서 사용되는 데이터 모델 중 하나입니다.
DAG는 다음과 같은 성질을 가지고 있습니다.
- 노드와 노드가 화살표로 연결(방향성)
- 화살표를 아무리 따라가도 동일 노드로는 되돌아오지 않음(비순환)
실행해야 할 태스크를 DAG로 정의하면 태스크 간의 의존 관계를 유지하면서 실행 순서를 결정하는 것이 가능합니다.
즉, 분산 시스템의 내부에서 높은 효율로 실행할 수 있도록 합니다.
데이터 플로우와 워크플로 조합
데이터 플로우에서 프로그래밍할 수 있게 되면, 데이터의 입출력 모두 하나의 DAG로 기술할 수 있습니다.
예를 들어, 배치 형의 데이터 플로우를 스크립트화 해두면 데이터 구조화나 데이터 마트 구축이라는 프로세스를 단순 태스크로 워크플로에서 호출할 수 있습니다.
스트리밍형 데이터 플로우
스트리밍형 데이터 플로우도 DAG를 사용합니다.
분산 스토리지를 거치지 않고 처리를 계속하는 것을 스트림 처리라고 합니다.
스트림 처리는 실시간성이 우수하지만, 과거의 데이터를 취급하는 데에는 부적합합니다.
스트림 처리에는 잠재적인 두가지 문제가 있습니다.
바로 틀린 결과를 어떻게 수정할 것인가와 과거의 결과를 수정하고 싶을 때 어떻게 할 것인가입니다.
이러한 문제를에 대한 전통적인 대처 방법은 스트림 처리와는 별개로 배치 처리를 실행시켜 후자의 결과가 옳다고 하는 것입니다.
예를 들어, 일별 보고서를 속보 값으로 하고 월별 보고서를 확정값으로 하는 것입니다.
이 방법을 이용한 것에 람다 아키텍처와 카파 아키텍처가 있습니다.
람다 아키텍처
람다 아키텍처는 배치 처리를 조합시켜 2계통의 데이터 처리 구조를 가지고 있습니다.
람다 아키텍처는 3가지 레이어를 가지고 있습니다.
모든 데이터는 반드시 배치 레이어에서처리합니다.
과거의 데이터를 장기적인 스토리지에 축적하고, 여러번 다시 집계할 수 있게 합니다.
배치 레이어는 대규모 배치 처리를 실행할 수 있지만 1회 처리에는 긴 시간이 걸립니다.
배치 처리 결과는 서빙 레이어를 통해서 접근합니다.
여기에 응답이 빠른 데이터베이스를 설치하여 집계 결과를 바로 추출하도록 합니다.
서빙 레이어에서 얻어진 결과를 배치 뷰라고 합니다.
배치 뷰는 정기적으로 업데이트 되는 것이므로 실시간 정보를 얻을 수 없습니다.
다른 경로인 스피드 레이어는 스트림 처리를 합니다.
스피드 레이어에서 얻은 결과를 실시간 뷰라고 합니다.
실시간 뷰는 배치 뷰가 업데이트될 동안까지만 이용되고 오래된 데이터는 순서대로 삭제됩니다.
마지막에는 배치 뷰와 실시간 뷰 모두를 조합시키는 형태로 쿼리를 실행합니다.
하지만 람다 아키텍처는 시스템을 복잡하게 해서 나쁜 개발 효율을 가지고 있습니다.
카파 아키텍처
람다 아키텍처에서 배치 레이어와 서빙 레이어를 완전히 제거하고 스피드 레이어만 남겨서 단순화한 것입니다.
카파 아키텍처는 메시지 브로커의 데이터 보관 기간을 충분히 길게 하여 무슨 문제가 일어났을 때는 메시지 배송 시간을 과거로 다시 설정합니다.
그러면 과거의 데이터가 다시 스트림 처리로 흘러 들어 실질적으로 재실행이 이루어집니다.
즉, 배치 처리와 같은 과거 데이터의 일괄 처리를 스트림 처리만으로 실행할 수 있습니다.
하지만 이렇게 하면 부하가 높아지는 단점이 있습니다.
예를 들어, 스트림 처리의 데이터 플로우에 대량의 과거 데이터를 흘려보내면, 평상시와 비교해 몇 배 또는 몇십 배의 계산 자원을 일시적으로 소비하게 됩니다.
아웃 오브 오더의 데이터 처리
앞 글에서 설명한 이벤트 시간과 프로세스 시간의 차이 때문에 스트림 처리는 올바른 집계 결과를 얻기 힘듭니다.
이때 이벤트 시간과 프로세스 시간 차이 때문에 생기는 문제를 기술적으로는 아웃 오브 오더의 데이터 문제라고 불립니다.
이벤트 시간 윈도잉
스트림 처리에서는 종종 시간을 일정 간격으로 나누어 윈도우를 만들고 그 안에서 데이터 집계를 합니다.
예를 들어, 과거 1시간의 이벤트 수 추이를 그래프로 만들고 싶으면, 데이터를 1분 간격인 60개의 윈도우로 나누어 각각의 윈도우로 이벤트 수를 셉니다.
이벤트 시간에 의해 윈도우를 나누는 것을 이벤트 시간 윈도윙이라 합니다.
과거 이벤트의 상태를 보관하면서, 데이터가 도달할 때마다 해당하는 윈도우를 재집계 합니다.
데이터를 무한히 계속 보관할 수는 없으므로 일정 이상 늦게 온 데이터는 무시하게 됩니다.
'to become 데이터 엔지니어 > 간단한 정리' 카테고리의 다른 글
빅데이터의 축적 (0) | 2023.01.06 |
---|---|
빅데이터의 분산 처리 (0) | 2023.01.05 |
빅데이터 탐색 (0) | 2022.12.29 |
스몰 데이터 분석 (0) | 2022.12.29 |
데이터 파이프라인 (0) | 2022.12.28 |