풀(Pool)로 태스크 동시 실행을 제한하기
풀(Pool)로 태스크 동시 실행을 제한하기
백엔드 시스템이나 외부 API는 한 번에 너무 많은 요청이 몰리면 금방 숨이 차요. Airflow의 풀(Pool) 개념을 쓰면 임의의 태스크 묶음에 실행 병렬도를 제한해서, 과부하로 시스템이 무너지는 걸 미리 막을 수 있어요.
본문
풀의 기본 아이디어
어떤 시스템은 너무 많은 프로세스가 동시에 부딪히면 과부하에 걸리기 쉬워요. 풀은 이런 상황에서 태스크들의 실행 병렬도를 제한하는 장치예요. 특정 태스크 집합이 한꺼번에 달려드는 걸 막아서, 연산 파이프라인이 안정적으로 돌아가도록 도와줘요.
풀의 목록은 UI에서 관리할 수 있어요. 메뉴 → Admin → Pools로 들어가면, 풀 이름을 짓고 워커 슬롯(worker slots) 수를 정해줄 수 있어요. 여기서 풀이 점유 슬롯 계산에 지연 가능(deferred) 태스크를 포함할지도 함께 정할 수 있어요.
태스크는 pool 파라미터로 기존 풀 중 하나에 연결해요:
aggregate_db_message_job = BashOperator(
task_id="aggregate_db_message_job",
execution_timeout=timedelta(hours=3),
pool="ep_data_pipeline_db_msg_agg",
bash_command=aggregate_db_message_job_cmd,
dag=dag,
)
aggregate_db_message_job.set_upstream(wait_for_empty_queue)
태스크는 슬롯이 차오르는 동안에도 평소처럼 스케줄링돼요. 태스크 하나가 점유하는 슬롯 수는 pool_slots로 조정할 수 있어요. 용량이 꽉 차면 실행 가능한 태스크는 큐에 쌓이고, UI에 그 상태가 그대로 표시돼요. 슬롯이 다시 비워지면, 큐에 있던 태스크는 자기와 자손 태스크의 우선 가중치(Priority Weights)에 따라 순서대로 실행되기 시작해요.
풀을 지정하지 않으면 어떻게 되나요?
태스크에 풀을 따로 지정하지 않으면 기본 풀인 default_pool에 배정돼요. default_pool은 처음에 128개 슬롯으로 초기화되며, UI나 CLI에서 수정할 수 있어요. 다만 이 풀 자체는 삭제할 수 없어요.
슬롯을 여러 개 쓰면서 무거운 태스크 다루기
Airflow 태스크는 기본적으로 슬롯 하나만 점유하지만, pool_slots 인자를 주면 더 많은 슬롯을 차지하게 만들 수 있어요. 같은 풀 안에 속한 태스크들이 "계산 무게"가 서로 다른 경우에 특히 유용해요.
예를 들어 슬롯이 2개인 풀을 Pool(pool='maintenance', slots=2)처럼 만들었다고 해볼게요. 그리고 태스크들을 이렇게 구성해요:
BashOperator(
task_id="heavy_task",
bash_command="bash backup_data.sh",
pool_slots=2,
pool="maintenance",
)
BashOperator(
task_id="light_task1",
bash_command="bash check_files.sh",
pool_slots=1,
pool="maintenance",
)
무거운 태스크(heavy_task)는 2개 슬롯을 쓰도록 설정했기 때문에, 얘가 돌아가는 동안 풀은 전부 차요. 그래서 가벼운 태스크들은 무거운 태스크가 끝날 때까지 큐에서 기다려야 해요. 반대로 가벼운 태스크 둘은 각각 슬롯 하나씩만 쓰니, 무거운 태스크가 슬롯 두 개를 확보할 때까지는 서로 같이 돌 수 있어요.
풀과 SubDAG의 주의점
풀과 SubDAG는 생각처럼 자연스럽게 맞물리지 않아요. SubDAG 최상위 레벨에 풀을 설정해도 그 풀은 적용되지 않으니 주의해야 해요. 풀은 반드시 SubDAG 안쪽 태스크들에 직접 설정해야 해요.