지난 글에서는 복잡한 대규모 환경을 위한 하이브리드 Executor들을 살펴보았습니다. 하지만 현실적으로 인프라 예산과 관리 인력이 제한된 상황에서 가장 가성비가 좋은 선택은 고성능 VM 한 대에 LocalExecutor를 올리고 자원을 극한으로 활용하는 '스케일 업(Scale-up)' 전략입니다.

Airflow의 기본 설정은 매우 보수적이기 때문에, 서버 스펙이 아무리 좋아도 설정을 바꾸지 않으면 VM의 자원을 절반도 쓰지 못하고 파이프라인이 밀릴 수 있습니다. 오늘은 DA(Data Architect) 관점에서 단일 VM을 가장 효율적으로 "쥐어짜는" 핵심 튜닝 포인트 3가지를 공유합니다.


1. Airflow 동시성(Concurrency) 4대장 설정하기

LocalExecutor는 단일 서버 내에서 멀티프로세싱(Multiprocessing)으로 동작합니다. 즉, 설정한 값만큼 자식 프로세스를 띄워 작업을 처리하므로 아래 4가지 핵심 설정값을 VM 스펙에 맞춰 상향 조정해야 합니다.

① parallelism (전체 태스크 동시 실행 제한)

  • 의미: Airflow 시스템 전체에서 동시에 돌아갈 수 있는 최대 태스크 수입니다.
  • 튜닝 가이드: 기본값은 32입니다. 만약 우리 파이프라인이 CPU 연산 중심이라면 (서버 CPU 코어 수 * 2) 정도로 잡고, 네트워크 I/O(DB 조회, API 호출 등) 중심이라면 (서버 CPU 코어 수 * 4) 이상으로 과감하게 늘려도 됩니다.
  • 설정 예시 (16코어 VM 기준): parallelism = 64

② worker_concurrency (LocalExecutor 기준 최대 프로세스 수)

  • 의미: LocalExecutor 환경에서는 이 값이 스케줄러가 동시에 띄울 수 있는 최대 자식 프로세스(Worker) 수를 결정합니다.
  • 튜닝 가이드: 기본값은 16입니다. 보통 parallelism과 동일하거나 약간 작은 수준으로 맞추어, 단일 실행기가 서버 자원을 최대한 활용할 수 있도록 병목을 풀어줍니다.
  • 설정 예시: worker_concurrency = 64

③ max_active_tasks_per_dag (DAG당 동시 태스크 제한)

  • 의미: 하나의 DAG 안에서 동시에 실행될 수 있는 최대 태스크 수입니다. (과거 버전의 dag_concurrency)
  • 튜닝 가이드: 기본값은 16입니다. 하나의 DAG 안에 수십 개의 Task가 병렬(Parallel Grid) 구조로 배치되어 있다면 이 값을 늘려주어야 막히지 않고 한 번에 쏟아져 나갑니다.
  • 설정 예시: max_active_tasks_per_dag = 32

④ max_active_runs_per_dag (DAG당 동시 실행 Run 제한)

  • 의미: 하나의 DAG가 동시에 가동될 수 있는 최대 '시간대(Run)'의 수입니다.
  • 중요성: 과거 실패한 데이터를 재처리하는 백필(Backfill) 작업을 돌릴 때 매우 중요합니다. 이 값이 기본값(1)이면 어제, 그저께 데이터를 한꺼번에 돌려도 하루치씩 순서대로 실행됩니다.
  • 설정 예시: max_active_runs_per_dag = 3 (동시 백필 필요 시 상향)

2. 숨은 병목의 주범: Meta DB 커넥션 풀(Pool) 풀기

많은 엔지니어들이 VM 스펙과 Airflow 설정만 높여놓고 정작 데이터베이스(MySQL/PostgreSQL) 연결 개수를 늘리지 않아 태스크가 DB Connection Timeout으로 터지는 실수를 범합니다. LocalExecutor는 각 태스크 프로세스가 메타 DB에 직접 붙기 때문에 커넥션을 많이 먹습니다.

airflow.cfg에서 아래 두 가지 설정을 반드시 세트로 늘려주어야 합니다.

  • sql_alchemy_pool_size = 30 (메타 DB와 연결할 기본 커넥션 풀 크기 / 기본값: 5)
  • sql_alchemy_max_overflow = 20 (풀이 가득 찼을 때 초과 허용할 수 있는 커넥션 수 / 기본값: 10)

■ 주의 (체크포인트)
Airflow 설정을 이렇게 높였다면, 메타 DB 자체(MySQL의 max_connections 등)의 인바운드 커넥션 제한도 함께 늘려주어야 합니다. Airflow가 50개의 커넥션을 맺으려는데 DB가 20개만 허용하면 에러가 발생합니다.


3. OS 및 태스크 레벨에서의 자원 격리 전략

단일 VM 운영의 최대 약점은 "Task 하나가 미쳐서 서버 전체를 죽일 수 있다"는 점입니다. 이를 방지하기 위한 최소한의 안전장치가 필요합니다.

  • Heavy 작업은 별도 프로세스로 분리: Airflow의 Task 내에서 파이썬 코드로 수백만 건의 판다스(Pandas) 연산을 직접 수행하면 VM 메모리가 순식간에 고갈(OOM Error)되어 스케줄러까지 같이 죽습니다. heavy한 데이터 연산은 BashOperator나 DockerOperator를 통해 독립된 프로세스로 실행하거나, 외부 DB(쿼리 중심)에 위임하는 것이 좋습니다.
  • 임시 파일 및 로그 정리: 단일 VM을 쓰다 보면 /tmp 폴더나 Airflow 태스크 로그가 쌓여 디스크 풀(Full)이 나면서 서버가 멈추는 경우가 많습니다. 매일 오래된 로그를 지워주는 청소용 DAG(DbCleanOperator 등)를 필수로 가동하세요.

단일 VM 쥐어짜기 설정 요약 가이드

설정 항목 기본값 추천 세팅 가이드 (Scale-up 최적화)
parallelism 32 CPU 코어 수 * 2 ~ 4 (I/O Bound 워크로드일수록 높게)
worker_concurrency 16 parallelism 설정값과 동기화
max_active_tasks_per_dag 16 대형 DAG 내 병렬 태스크 수에 맞춰 32~64로 상향
sql_alchemy_pool_size 5 동시 태스크 수 증가에 맞춰 30~50 이상 필수 상향

"쿠버네티스나 Celery가 좋다는 말에 휩쓸려 무작정 인프라를 복잡하게 만들 필요는 없습니다. 8코어/16코어 수준의 VM 한 대라도 아키텍처적 병목(Concurrency, DB Pool)만 제대로 풀어주면 하루 수만 개의 일반적인 ETL 태스크는 거뜬히 소화해낼 수 있습니다."

+ Recent posts