테크블로그014 : 누리미디어 채용 누리미디어 테크블로그

테크블로그014 : 누리미디어 채용

누리미디어 테크블로그

about 1

Workflow 관리 툴 Prefect 도입

제목없음

about 1

안녕하세요. 누리미디어 백엔드 개발자입니다. 저는 신규 프로젝트로 KRpia AI 베타 버전을 맡게 되었습니다. 국사편찬위원회의 방대한 XML 데이터를 파싱하고, LLM을 활용해 요약·번역·임베딩을 수행하는 이 서비스는 각 단계의 의존성 관리가 핵심입니다. 이 복잡한 여정을 관리하기 위해 제가 선택한 워크플로우 오케스트레이션 도구, Prefect 도입기를 공유합니다.

제목없음

제목없음

워크플로우 엔진 도입, 왜 필요했을까?

초기에는 단순히 파이썬 스크립트를 순차적으로 실행하는 방식을 고민했습니다. 하지만 실제 구현에 들어가자 다음과 같은 현실적인 문제들에 직면했습니다. 파편화된 배치 관리의 한계 수많은 전처리 스크립트가 각기 다른 시점에 실행되어야 하는데, 이를 크론탭(Crontab)이나 수동으로 관리하면 장애 발생 시 어느 지점에서 멈췄는지 파악하기가 매우 어렵습니다. 비동기 서비스의 의존성 해결 Gemini Batch와 같은 외부 API는 작업 요청 후 완료까지 수 시간이 걸립니다. "A 작업이 끝나야 B 작업을 시작한다"는 단순한 로직을 구현하기 위해 복잡한 상태 체크 로직을 매번 코딩해야 했습니다. 부분 실패에 대한 복구 10만 건의 데이터 중 9만 9천 건이 성공하고 1천 건이 실패했을 때, 전체를 다시 돌리지 않고 실패한 부분만 골라 재시도할 수 있는 견고한 시스템이 필요했습니다. 이러한 문제를 해결하기 위해 워크플로우 오케스트레이션 도구 도입을 결정했고, 여러 후보군 중 최종적으로 Prefect를 선택하게 되었습니다.

제목없음

제목없음

1. 왜 Airflow가 아닌 Prefect인가?

워크플로우 도구의 대세는 단연 Airflow입니다. 하지만 신규 프로젝트를 빠르게 궤도에 올려야 하는 상황에서 저희 팀은 다음과 같은 이유로 Prefect를 선택했습니다.

첫째, 압도적으로 낮은 러닝커브 (Low Learning Curve)Airflow는 DAG를 정의하기 위해 전용 오퍼레이터(Operator)와 복잡한 설정을 학습해야 합니다. 반면 Prefect는 Pythonic 그 자체입니다. 기존에 작성한 함수 위에 @flow, @task 데코레이터만 추가하면 즉시 워크플로우로 변신합니다. 덕분에 인프라 학습 시간을 줄이고 비즈니스 로직 구현에 더 집중할 수 있었습니다. 둘째, 비동기 외부 서비스(Gemini-Batch)의 상태 관리KRpia AI는 LLM 처리를 위해 Gemini-Batch API를 활용합니다. 이 API는 요청 후 결과가 나올 때까지 시간이 걸리는 비동기 방식입니다. 단순한 크론탭(Crontab)으로는 "작업이 끝났는지" 주기적으로 체크하고 다음 스텝으로 넘겨주는 로직을 구현하기 까다롭습니다. Prefect는 이러한 비동기 외부 서비스의 상태를 폴링(Polling)하고, 완료 시점에 맞춰 후속 태스크(요약, 임베딩 등)를 트리거하는 상태 관리 스케줄러로서 최적의 대안이었습니다. 셋째, 유연한 Chunk 단위 배치 실행방대한 XML 데이터를 한꺼번에 처리하면 메모리 부하와 타임아웃 문제가 발생합니다. 저희는 데이터를 Chunk 단위로 나누어 실행하고, 각 Chunk의 성공/실패 여부를 개별적으로 관리해야 했습니다. Prefect는 동적 파라미터 전달이 자유로워, 데이터를 쪼개어 병렬로 실행하고 상태를 추적하는 구조를 매우 쉽게 구현할 수 있었습니다.

제목없음

제목없음

2. Prefect와 Airflow: 한눈에 비교하기

제목없음

제목없음

3. KRpia AI의 Prefect 활용 전략

Python 기반의 LLM 파이프라인 최적화현재 KRpia AI는 전 과정을 Python으로 구축했습니다. XML 파싱부터 Gemini API 연동, Vector DB 임베딩까지의 전 과정을 Prefect Flow로 묶어 관리합니다. 특히 실패한 Chunk만 골라 재시도(retries)하거나, 특정 구간만 다시 실행하는 것이 가능해져 운영 공수가 획기적으로 줄어듭니다. 미래를 위한 설계: 이기종 배치(Java 등) 확장성현재는 KRpia AI 배치는 Python이지만, 향후 성능 최적화나 기존 시스템 통합을 위해 Java 배치 도입을 고려하고 있습니다. Prefect는 ShellTask 등을 통해 외부 프로세스를 실행하는 기능이 강력합니다. 언어가 바뀌더라도 전체 워크플로우의 '관제탑' 역할은 Prefect가 수행하므로, 향후 기술 스택이 확장되어도 파이프라인의 일관성을 유지할 수 있는 기반을 마련해두었습니다.

제목없음

제목없음

4. KRpia AI 파이프라인 구현

KRpia AI 파이프라인은 단순히 코드를 실행하는 것을 넘어,"대량의 데이터를 어떻게 안정적으로 처리할 것인가"에 대한 고민을 Prefect의 기능을 활용해 해결했습니다.

4.1 비동기 분리 Flow 아키텍처Gemini Batch는 작업 완료까지 수 시간이 걸릴 수 있습니다. 이를 하나의 Flow에서 기다리는(Blocking) 것은 자원 낭비입니다. 저희는 이를 3단계로 분리했습니다. Submit Flow: DB에서 대상 기사를 추출, Chunk 단위로 JSONL을 생성해 Gemini에 던지고 즉시 종료됩니다. Monitor Flow: 5분마다 실행되며 Gemini의 상태만 체크합니다. Validate Flow: 작업이 완료되면 자동으로 트리거되어 결과를 검증하고 Elasticsearch에 저장합니다.

4.2 Python 코드 스니펫: 비동기 상태 폴링 및 트리거이 파이프라인의 핵심인 Monitor Flow에서 완료된 작업을 감지하고 다음 단계로 넘겨주는 실제 로직의 추상화된 예시입니다.

4.3 Chunk 단위의 세밀한 상태 관리 (State-Driven)저희는 기사 단위의 상태(status)와 배치 잡 단위의 상태(state)를 이중으로 관리하여 장애 대응력을 높였습니다.

성공 시: Elasticsearch에 LLM 결과물을 저장하고 PostgreSQL의 상태를 벌크로 업데이트합니다. 실패 시: Pydantic 검증에 실패한 기사는 retry_count를 체크하여 자동으로 PARSED 상태로 복원, 다음 배치에 포함되도록 설계했습니다.

제목없음

제목없음

5. 시스템 아키텍처 및 운영 환경 구축

5.1 서버(Server)와 실행부(Worker)의 물리적 분리안정성을 위해 관리 대시보드인 Server와 실제 배치가 수행되는 Worker 인스턴스를 분리했습니다.

5.2 단일 서버 내 다중 워커(N-Workers) 운영리소스 효율성을 위해 하나의 서버 내에 여러 개의 워커 프로세스를 독립적으로 실행합니다. 자원 격리: 각 워커는 독립된 파이썬 프로세스로 돌아가며, 한 워커가 죽어도 다른 워커가 작업을 이어받아 'Single Point of Failure'를 방지합니다. 동시성 제어: Work Pool의 Concurrency Limit 설정을 통해 서버 자원 고갈을 막습니다.

시스템 아키텍처 구조

제목없음

제목없음

6. Prefect UI에서 배포 실행하기

코드로 작성한 Flow를 서버에 배포(Deploy)했다면, 이제 Prefect UI를 통해 시각적으로 관리하고 실행할 차례입니다. 구체적인 실행 단계와 모니터링 방법은 다음과 같습니다.

(1) 배포 항목(Deployments) 선택Prefect Dashboard 좌측 메뉴에서 Deployments를 선택합니다. 등록된 리스트 중 실행을 원하는 항목(예: translate-submit-dev)을 클릭하여 상세 페이지로 진입합니다.

(2) 배치 실행 (Run)상세 페이지 우측 상단의 Run 버튼을 클릭하면 두 가지 옵션이 나타납니다. Quick run: 설정된 기본 파라미터로 즉시 실행합니다. Custom run: 이번 실행에만 적용할 파라미터(데이터 범위, 모델 종류 등)를 직접 수정하여 실행할 수 있습니다.

(3) 파라미터 설정 및 실행오른쪽 하단 실행을 누르면 배포 대기열(Next Run)에 잡이 등록됩니다. 워커(Worker)가 해당 잡을 가져가면 상태가 Scheduled에서 Running으로 변경됩니다.

(4) 실시간 모니터링 및 로그 확인실행 중인 잡의 **ID(Flow Run Name)**를 클릭하면 상세 모니터링 화면으로 이동합니다. 여기서 다음과 같은 정보를 실시간으로 확인할 수 있습니다.

대기열 등록 후 대기 중

실행 중의 경우

Logs: 파이썬 코드 내의 Print 문이나 Logging 라이브러리로 출력되는 모든 로그를 실시간으로 확인하여 에러 발생 지점을 즉시 파악할 수 있습니다. Task Runs: Flow 안에 정의된 각각의 Task들이 어떤 순서로 실행되고 있는지, 특정 Task에서 병목이 발생하지 않는지 시각적으로 확인 가능합니다. Parameters: 해당 잡 실행 시 어떤 설정값이 사용되었는지 다시 확인할 수 있습니다.

(5) 결과 확인 및 사후 관리작업이 완료되면 Completed 상태로 변하며, 만약 실패(Failed)할 경우 어느 지점에서 에러가 발생했는지 로그를 통해 분석할 수 있습니다. 특히 재시도(Retries) 설정이 되어 있다면, 실패 시 자동으로 다시 실행되는 과정도 이 화면에서 한눈에 볼 수 있습니다.

제목없음

제목없음

7. 적용 후 개선: 가시성과 복구 능력

대시보드를 통한 관제Prefect UI를 통해 현재 몇 개의 청크가 Gemini 큐에 쌓여 있는지, 어떤 청크에서 검증 에러(schema_validation)가 발생했는지 한눈에 파악할 수 있게 됩니다. 유연한 재시도 메커니즘기존에는 배치 하나가 실패하면 전체를 다시 돌려야 했지만, 이제는 검증에 실패한 특정 기사만 자동으로 다음 배치에 재포함됩니다. 또한 parent_chunk_id 추적을 통해 번역(Translate)에서 해설(Summary)로 이어지는 관계를 명확히 유지할 수 있습니다. 미래 확장성: 이기종 배치의 통합 관제탑 (Control Tower) 현재는 Python 위주지만, 궁극적으로는 파편화된 사내 Java 배치들의 통합 관리를 목표로 합니다. 기존 배치 이식: 크론탭 등으로 흩어져 관리가 어려웠던 기존 Java 배치들을 Prefect로 편입시켜 가시성을 확보할 계획입니다. 언어 통합 워크플로우: 성능 중심의 Java 파싱과 유연한 Python LLM 로직이 섞여 있더라도, ShellTask 등을 통해 단일 관제점(Single Point of Control)에서 의존성과 재시도를 통합 관리하는 운영 환경을 구축할 수 있습니다.

제목없음

제목없음

마치며

기술을 선택할 때 가장 중요한 것은 "우리 팀의 속도와 요구사항에 맞는가"입니다. Prefect는 낮은 러닝커브와 강력한 비동기 상태 관리 기능을 통해 KRpia AI 프로젝트가 안정적으로 안착하는 데 핵심적인 역할을 할 것으로 기대합니다.

제목없음

people

채용 공고 보러가기 ↗︎

img

Created by