Dag File Processing — 파싱 파이프라인과 성능 튜닝
Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation administration-and-deployment/dagfile-processing.rst (전체)
이 모듈을 다 읽으면
- DagFileProcessorManager와 DagFileProcessorProcess 각각의 역할과 처리 단계를 구분해 설명할 수 있다
- Dag processor 성능에 영향을 주는 자원(파일시스템, DB 커넥션, CPU, 메모리) 각각의 병목 신호를 판단할 수 있다
- min_file_process_interval을 늘리거나 parsing_processes를 늘렸을 때 어떤 트레이드오프가 생기는지 설명할 수 있다
- PGBouncer가 Postgres 기반 Airflow 배포에서 왜 필요해지는지 설명할 수 있다
Dag File Processing은 파이썬으로 작성된 Dag 파일을 읽어 스케줄러가 스케줄링할 수 있는 형태로 만드는 과정이다. DagFileProcessorManager가 어떤 파일을 언제 처리할지 결정하는 무한 루프를 돌리고, DagFileProcessorProcess가 개별 파일을 실제로 Dag 객체로 변환한다. 성능은 파일시스템·DB 커넥션·CPU·메모리라는 네 자원의 병목에 좌우되며, 각 설정값을 조정하는 것은 항상 '더 빠른 반영'과 '더 낮은 자원 사용' 사이의 트레이드오프다.
두 프로세스와 각각의 처리 단계
Dag File Processing은 Dag를 정의하는 파이썬 파일을 읽어, 스케줄러가 스케줄링할 수 있도록 저장하는 과정을 가리킨다. 여기에는 두 가지 핵심 컴포넌트가 관여한다. ``DagFileProcessorManager``는 어떤 파일을 처리해야 하는지 결정하는 무한 루프를 도는 프로세스이고, ``DagFileProcessorProcess``는 개별 파일 하나를 하나 이상의 Dag 객체로 변환하기 위해 시작되는 별도의 프로세스다. ``DagFileProcessorManager``는 사용자 코드를 실행하므로, ``airflow dag-processor`` CLI 명령으로 독립 프로세스로 실행된다.
``DagFileProcessorManager``의 처리 단계는 다음과 같다: (1) 새 파일 확인 — 마지막 Dag 새로고침 이후 경과 시간이 ``[dag_processor] refresh_interval``을 넘으면 파일 경로 목록을 갱신한다. (2) 최근 처리된 파일 제외 — ``min_file_process_interval``보다 최근에 처리되었고 수정되지 않은 파일은 제외한다. (3) 파일 경로 큐잉 — 발견된 파일을 처리 큐에 추가한다. (4) 파일 처리 — 파일마다 새 ``DagFileProcessorProcess``를 시작하되, ``[dag_processor] parsing_processes``로 지정한 최대치까지만 동시에 실행한다. (5) 결과 수집 — 완료된 Dag processor들로부터 결과를 모은다. (6) 통계 로깅 — 통계를 출력하고 ``dag_processing.total_parse_time`` 메트릭을 발행한다.
``DagFileProcessorProcess``의 처리 단계는: (1) 파일 처리 — 전체 과정이 ``dag_file_processor_timeout`` 안에 끝나야 한다. (2) Dag 파일을 파이썬 모듈로 로드 — ``dagbag_import_timeout`` 안에 완료되어야 한다. (3) 모듈 처리 — 파이썬 모듈 안에서 Dag 객체를 찾는다. (4) DagBag 반환 — 발견한 Dag 객체 목록을 ``DagFileProcessorManager``에 제공한다.
핵심 포인트
- DagFileProcessorManager는 어떤 파일을 처리할지 결정하는 무한 루프이고, DagFileProcessorProcess는 파일 하나를 실제로 Dag 객체로 변환하는 별도 프로세스다
- Manager의 처리 순서는 새 파일 확인 -> 최근 처리분 제외 -> 큐잉 -> parsing_processes 한도 내에서 Process 실행 -> 결과 수집 -> 통계 로깅이다
- Process는 dag_file_processor_timeout 안에 전체 과정을, dagbag_import_timeout 안에 모듈 임포트를 마쳐야 한다
성능에 영향을 주는 자원과 관찰 방법
Dag processor 성능 튜닝은 배포 종류(공유 파일시스템 종류·속도, 가용 메모리·CPU·네트워크 대역폭), Dag 구조(파일 수, 파일당 Dag 수, 파일 크기·복잡도, top-level 코드에서 무거운 임포트나 처리를 하는지), Dag processor 설정(프로세서 수, 파싱 프로세스 수, 재파싱 대기 시간, 루프당 콜백 수)이라는 세 축에 걸쳐 있다.
튜닝 접근법은 일반적인 성능 개선과 동일하다 — 자신이 쓰는 모니터링 도구로 시스템을 관찰하고, 어떤 성능 측면을 개선할지 정하고, CPU·메모리·I/O 중 어디가 병목인지 관찰한 뒤, 관찰 결과를 바탕으로 다음 개선을 결정하고 다시 관찰하는 과정을 반복한다. 예를 들어 새 Dag가 30초 지연되어 파싱되는 것을 감수하고 CPU 사용량을 낮출지, 아니면 Dag가 폴더에 나타나자마자 거의 즉시 파싱되길 원하고 그만큼 CPU를 더 쓸지는 사용자가 결정할 몫이다.
주의 깊게 봐야 할 자원은 다음과 같다. 파일시스템 성능 — Dag processor는 흔히 공유/분산 파일시스템(NFS, CIFS, EFS, GCS fuse, Azure File System 등)에 있는 파이썬 파일을 지속적으로 읽고 재파싱한다. EFS의 IOPS를 늘리면(더 비용을 지불하고) 파싱 안정성·속도가 극적으로 개선되었다는 일화적 증거들이 있다. 파일시스템이 병목이라면, Dag를 이미지에 임베드하거나 GitSync로 배포하는 방식이 대안이 될 수 있다 — 파일이 로컬에 있어 분산 파일시스템을 거칠 필요가 없고, 특히 SSD를 쓰는 로컬 스토리지라면 가능한 한 빠르다.
DB 커넥션·사용량도 성능을 높이려 할수록 문제가 될 수 있다. Airflow는 'DB 커넥션에 굶주린' 편이라, Dag 수와 병렬 처리량이 늘수록 더 많은 커넥션이 열린다. MySQL은 커넥션 처리가 스레드 기반이라 대체로 문제가 되지 않지만, Postgres는 프로세스 기반이라 중간 규모 이상의 Airflow 설치에서는 ``PGBouncer``를 DB 앞단 프록시로 두는 것이 일반적으로 권장된다(공식 Helm Chart도 PGBouncer를 기본 지원한다).
CPU 사용량은 파이썬 Dag 파일을 파싱·실행하는 File Processor에서 가장 중요하다. Dag 수가 많고 지속적으로 파싱이 트리거되면 CPU 사용량이 커질 수 있다 — ``min_file_process_interval``을 늘려 완화할 수 있지만, 이는 파일 변경사항이 더 느리게 반영된다는 트레이드오프를 수반한다. Dag 구성을 최적화하고 외부 데이터 소스 접근을 피하는 것이 CPU 사용량 개선의 가장 좋은 방법이며, CPU가 더 있다면 ``parsing_processes``(처리 스레드 수)를 늘릴 수 있다.
메모리도 성능을 짜내려 할수록 크게 늘어날 수 있다. 부하를 처리하는 프로세스 수를 늘려 성능을 얻는 경우가 많은데, 각 프로세스는 파이썬 인터프리터 전체와 임포트된 다수 클래스, 임시 인메모리 저장소를 필요로 한다. Airflow는 forking과 copy-on-write 메모리로 많은 부분을 최적화하지만, fork 이후 새 클래스를 임포트하면 추가 메모리 압박이 생길 수 있다. 시스템이 가진 메모리보다 많이 쓰는지(스왑 디스크 사용으로 이어져 성능이 극적으로 떨어짐) 관찰해야 하며, 이때는 'total memory used'가 아니라 'working memory'를 봐야 한다.
핵심 포인트
- 파일시스템 병목이 있다면 EFS IOPS 증설, 또는 Dag 이미지 임베딩·GitSync처럼 로컬 파일 접근으로 바꾸는 것이 대안이다
- Postgres 기반 배포에서는 프로세스 기반 커넥션 처리 특성상 PGBouncer를 프록시로 두는 것이 중간 규모 이상에서 사실상 표준 권장사항이다(Helm Chart 기본 지원)
- min_file_process_interval을 늘리면 CPU 사용량은 줄지만 Dag 변경 반영이 느려지고, parsing_processes를 늘리면 CPU가 여유 있을 때 처리량을 늘릴 수 있다
- 메모리 관찰 시 total memory가 아니라 working memory를 봐야 스왑으로 인한 성능 저하를 조기에 발견할 수 있다
개선 방향과 관련 설정
자원 사용 현황을 파악했다면 고려할 수 있는 개선 방향은 다음과 같다. top-level Dag 파이썬 코드의 파싱 로직·효율을 개선하고 복잡도를 줄인다 — 이 코드는 지속적으로 파싱되므로, 특히 외부 DB에 접근하는 것 같은 코드는 파싱 중에는 반드시 피해야 한다. 자원에 여유가 있다면 파싱 프로세스 수를 늘려 활용도를 높인다. CPU나 파일시스템 I/O가 한계에 달했다면 하드웨어 용량을 늘린다 — 공유 DB나 파일시스템이 병목이 아니라면 이것이 유일한 해법일 때도 많다. 'Dag processor 튜너블'들의 값을 바꿔가며 실험한다 — 예를 들어 CPU 사용량을 줄이고 싶다면 파일 처리 간격을 늘리되 새 Dag가 더 늦게 나타나는 대가를 치르는 식으로, 성능 튜닝은 대개 서로 다른 측면을 맞바꾸는 균형의 예술이다. 때로는 파싱 정렬 순서 같은 Dag processor의 동작 자체를 미세 조정해 배포별로 더 나은 결과를 얻기도 한다.
성능 관련 설정으로는 ``dag_processor.file_parsing_sort_mode``(Dag 파일을 나열·정렬해 파싱 순서를 정함), ``dag_processor.min_file_process_interval``(Dag 파일이 재파싱되는 간격 초, 낮출수록 CPU 사용량 증가), ``dag_processor.parsing_processes``(Dag processor가 병렬로 파일을 파싱하기 위해 띄우는 프로세스 수)가 있다.
핵심 포인트
- top-level Dag 코드에서 외부 DB 접근 등 무거운 처리를 피하는 것이 파싱 성능 개선의 가장 근본적인 방법이다
- 성능 튜닝은 대부분 트레이드오프이며(CPU vs 반영 속도 등), 관찰-결정-개선을 반복하는 것이 정석 접근이다
- file_parsing_sort_mode·min_file_process_interval·parsing_processes가 Dag processor 성능 튜닝의 핵심 설정이다