문제 해결
문제 해결 (Troubleshooting)
운영 중에 자주 마주치는 난해한 Task 실패 원인들을 정리한 문서예요. "Task state changed externally"나 프로세스 종료 신호 같은 흔한 상황들이 왜 발생하는지, 어떻게 대처해야 하는지 설명해 드려요.
출처: 문서
본문
난해한 Task 실패 (Obscure task failures)
Task 상태가 외부에서 변경됨 (Task state changed externally)
Task의 상태가 executor가 아닌 다른 컴포넌트에 의해 변경될 수 있는 잠재적 원인은 많아요. 그래서 Task Instance나 Scheduler 로그를 검토할 때 혼란스러울 수 있어요.
아래는 executor가 아닌 컴포넌트에 의해 Task 상태가 변경될 수 있는 예시 시나리오들이에요:
- 워커에서 Task의 DAG 파싱에 실패하면, 스케줄러가 Task를 실패로 표시할 수 있어요. 확인된다면 core.dagbag_import_timeout과 dag_processor.dag_file_processor_timeout을 늘리는 것을 고려해 보세요.
- Task가 scheduler.task_queued_timeout보다 오래 큐에 대기 중이면, 스케줄러가 Task를 실패로 표시해요.
- Task Instance의 heartbeat가 타임아웃되면, 스케줄러에 의해 실패로 표시돼요.
- 사용자가 Airflow UI에서 Task를 성공 또는 실패로 표시한 경우.
- 외부 스크립트나 프로세스가 Airflow REST API를 이용해 Task의 상태를 변경한 경우.
프로세스가 신호에 의해 종료됨 (Process terminated by signal)
때로는 Airflow 또는 인접 시스템이 Task Instance의 TaskRunner를 죽여서 Task Instance가 실패하게 돼요.
아래에서 몇 가지 흔한 경우를 살펴볼게요.
DAG run 타임아웃
DAG 정의에서 dagrun_timeout으로 DAG run 타임아웃을 지정할 수 있어요. 이 경우 Task 프로세스는 SIGTERM(exit code -15)으로 종료될 가능성이 높아요.
메모리 부족 오류 (Out of memory error, OOM)
Task 프로세스가 워커에 대해 너무 많은 메모리를 소비하면, 가장 좋은 경우는 SIGKILL(exit code -9)로 종료되는 거예요. 설정과 인프라에 따라 워커 전체가 OOM으로 인해 죽고, 그 후 heartbeat 실패로 Task들이 실패로 표시될 수도 있어요.
남아있는 Task supervisor 프로세스 (Lingering task supervisor processes)
매우 높은 동시성(high concurrency) 상황에서는 Task supervisor 내부의 소켓 핸들러가 Task 프로세스로부터 오는 최종 EOF 이벤트를 놓칠 수 있어요. 이런 경우 supervisor는 소켓이 아직 열려 있다고 생각해 종료되지 않아요. workers.socket_cleanup_timeout 옵션은 Task가 끝난 후 supervisor가 남은 소켓을 강제로 닫기 전에 기다리는 시간을 제어해요. 남아 있는 supervisor 프로세스가 보인다면 이 지연 시간을 늘리는 것을 고려해 보세요.