본문 바로가기
Airflow

[Airflow] KubernetesExecutor vs CeleryExecutor | LIM

by forestlim 2023. 9. 17.
728x90
반응형

KubernetesPodOperator 를 사용하게 되면서 자동으로 Executor 는 어떻게 설정해야 하는 것인가에 대한 고민이 시작되었다. 

물론 현재 설정되어 있는 CeleryExecutor로도 KubernetesPodOperator는 정상 동작한다. 

 

그럼 왜, KubernetesExecutor 를 사용하는 것일까?

 

기본 차이점

CeleryExecutor의 경우 여러대의 워커 머신을 사용해서 동시에 여러 작업을 분산 실행할 수 있다.

Celery는 메시지 브로커(RabbitMQ, Redis 등)를 사용하여 메시지를 전달하고, 워커 머신들은 이러한 메시지를 받아 작업을 실행한다.

아키텍처는 다음과 같다. 

https://engineering.linecorp.com/ko/blog/data-engineering-with-airflow-k8s-1

 

KubernetesExecutor의 경우 각 Airflow 작업을 Kubernetes의 개별 파드로 실행한다. 이 방식은 동적으로 스케일링이 가능하며 필요에 따라 리소스를 할당하거나 해제할 수 있다. 작업이 종료되면 해당 파드는 제거된다.

https://engineering.linecorp.com/ko/blog/data-engineering-with-airflow-k8s-2

즉, 정리하면 다음과 같다. 

Celery Executor의 경우 각 노드에 워커 파드가 계속해서 상주하고 있고 작업이 들어오면 작업을 분산 수행하고 작업이 종료되더라도 워커 파드는 계속해서 상주해있게 된다. 

 

하지만, KubernetesExecutor의 경우 작업을 실행할 때 워커 파드가 생성되고 작업이 종료되면 해당 워커 파드는 삭제된다. 



KubernetesPodOperator는 항상 KubernetesExecutor에서만 사용할 수 있는가?

정답은 아니다. KubernetesPodOperator는 CeleryExeuctor, LocalExecutor, KubernetesExecutor 모두 사용할 수 있다. 

다만, Airflow 가 kubernetes cluster 환경에서 구축되어 있어야 한다는 것이다. 

 

KubernetesPodOperator도 해당 작업을 실행하는 독립된 환경의 pod을 생성해서 작업한 후 해당 pod을 삭제한다.

이 개념은 KubernetesExecutor 가 작업을 실행시키는 과정과 동일하다. 

 

따라서, CeleryExecutor와 LocalExecutor를 사용하더라도 해당 작업에 해당하는 pod를 생성한 후 작업이 끝나면 해당 pod는 삭제되고 기존에 이미 생성되어 있는 workerpod는 그대로 남아있게 된다. 

 

즉, KubernetesExecutor는 모든 Operator를 실행시킬 때 pod을 새로 띄워서 작업 후 pod을 삭제한다고 보면 되고, 

다른 Executor의 경우에는 가지고 있는 worker pod에서 작업하고 해당 worker pod는 계속 남아있게 되지만 KubernetesPodOperator를 사용할 경우는 해당 worker pod을 추가로 생성해서 사용 후 없어진다고 보면 된다.

 

장단점 비교

[Kubernetes Executor]

👍 비용 절감의 효과

-> 워커 파드를 계속해서 띄워둘 필요가 없기 때문에

👍 독립된 환경에서 task 를 실행시킬 수 있기 때문에 dependecy 충돌에 대한 걱정이 없다.


👎 작업의 latency 가 발생할 수 있다.

-> 워커 파드를 task 가 실행될때마다 생성해야 되기 때문

👎 리소스 관리를 잘해야 한다. 

-> 자원이 무거운 작업에 몰릴 수 있기 때문

-> 워커 리소스 설정을 추가해 관리할 수 있다.

 

[Celery Executor]

👍 작업의 latency 가 거의 없다.

-> 워커 파드가 계속해서 상주해 있기 때문에 새로 띄울 필요가 없어 시작 지연이 거의 없다.


👎 운영복잡성

-> RabbitMQ, Redis 의 관리가 필요하다.

👎 고정 리소스 사용

-> 워커 파드가 계속해서 상주해 있기 때문에 고정 리소스 사용으로 비용이 더 발생할 수 있다. 

 

 

만약 DAG 가 많고 빠르게 이루어져야 하는 작업들이 많다면 CeleryExecutor 가 좋겠지만, KubernetesExecutor 를 잘 활용하면 독립된 환경에서 dependcy 충돌없이 비용도 절감할 수 있다는 측면에서 매력적으로 보인다. 

 

그렇다면 Kubernetes Executor 에서 Celery Executor의 Reddis나 RabbitMQ의 역할은 누가 하는 걸까?

Kubernetes Executor에서는 Kubernetes 클러스터 자체가 작업의 스케쥴링과 로드 밸런싱 역할을 한다. Kubernetes Executor를 사용할 때, 각 Airflow 작업은 Kubernetes Pod로 실행된다. 

 

Kubernetes Executor 를 사용하면 다음과 같은 방식으로 작업을 관리한다.

1. scheduling

  • Kubernetes 스케쥴러는 사용 가능한 노드 중에서 작업을 실행할 최적의 노드를 자동으로 선택한다. 이는 작업의 리소스 요구 사항과 노드의 사용 가능한 리소스를 기반으로 한다.

2. Load Balancing

  • Kubernetes는 서비스와 인그레스 리소스를 사용하여 로드 밸런싱을 수행할 수 있다. 이를 통해 네트워크 트래픽을 여러 파드 간에 자동으로 분배할 수 있다.

3. Auto Expand

  • Kubernetes는 클러스터의 리소스 사용량을 모니터링하고, 필요에 따라 자동으로 파드를 확장하거나 축소할 수 있다.

4. restart

  • Kubernetes는 실패한 파드를 자동으로 재시작할 수 있다. 또한 노드가 다운되면 파드를 다른 노드로 이동시킬 수 있다.

 

Celery Executor를 사용할 때 Auto Scaling 기능을 추가하고 싶다면

KEDA(Kubernetes Event-Driven Autosacling) 솔루션이 worker pod을 자동으로 scaling 할 수 있게 해준다.  KEDA를 사용하여 설정된 메트릭스나 이벤트(ex. RabbitMQ 또는 Kafka의 메시지 대기열 길이)를 기반으로 팟의 수를 자동으로 늘리거나 줄일 수 있다.

 

예를 들어, Celery Executor를 사용하는 Airflow에서 대기 중인 작업의 수가 증가하면, KEDA는 자동으로 추가 워커 팟을 생성(스케일 아웃)하여 대기 중인 작업을 더 빨리 처리할 수 있다. 반대로, 대기 중인 작업이 거의 없다면, KEDA는 불필요한 워커 팟을 제거(스케일 인)하여 리소스를 절약할 수 있다.

 

워커의 수는 Airflow 메타스토에서 다음과 같은 쿼리로 계산할 수 있다.

CEIL((Running + Queued tasks) / 16)

KEDA는 기본적으로 30초마다 데이터베이스에 쿼리하고 현재의 워커 수가 쿼리 결과와 다르고 셀러리 워커의 오토 스케일링 기능이 활성화되어 있다면 워커의 개수를 자동으로 변경한다.

 

Celery + KEDA vs Kubernetes Executor

둘 다 모두 수평적으로 스케일링할 수 있지만, Celery + KEDA 구성이 성능적 측면에서 더 좋다. 그 이유는 Celery + KEDA 로 구성할 경우 스케일 아웃할 수 있는 Celery Worker의 수를 지정해서 수행할 수 있고, 워커는 큐에 새로운 태스크가 도착하면 즉각 처리할 수 있기 때문이다. 

 

GCP Composer1 vs Composer2

Composer1은 기본적으로 Celery Executor를 사용하고 Kubernetes Cluster 위에 구축되어 있다. 

워커 팟의 개수를 늘릴 수는 있으나 자동으로 태스크의 상태에 따라 늘리거나 줄일 순 없다. 

 

Composer2도 Celery Executor를 사용하지만 Autoscaling 기능을 지원한다는 점에서 Composer1과는 다르다.

GKE의 autoscaling 기능을 기반으로 하며 이를 통해 효과적인 리소스 관리와 확장성을 달성할 수 있다

클러스터의 CPU 및 메모리 사용률을 모니터링하여 필요에 따라 노드의 수를 조정한다. 

 

만약 Composer 를 사용하는데 작업이 들쭉날쭉하고 한 번에 많은 리소스를 사용하고 그 외의 시간에는 많이 사용하지 않는다면 Composer2를 사용하는게 좀 더 비용 효율적일 것 같고, 하루종일 일정한 양의 리소스를 사용한다면 Composer1이 비용 효율적일 것 같다. 

728x90
반응형

댓글