프로그래밍 언어/파이썬

Celery와 FastAPI - 1

hyeseong-dev 2024. 3. 22. 00:06

Celery의 기본구성요소와 일반적인 Producer/Consumer 기반의 task queue에 대해 보겠습니다.

목표

  1. Celery 같은 task queue 사용 이유에 대해 알 수 있습니다.
  2. producer/consumer 모델을 알아보고, Celery와의 관련성을 알 수 있습니다.

Celery 사용 이유

Celery는 FastAPI, Django, Flask와 같은 Python 기반 웹 프레임워크와 자주 연동되는 오픈 소스, 비동기 태스크 큐입니다. 이는 전형적인 요청/응답 주기 외부에서 백그라운드 작업을 관리하기 위한 것입니다. 즉, 사용자가 작업이 끝나기를 기다리게 하지 않고 즉시 HTTP 응답을 반환한 다음, 프로세스를 백그라운드 태스크로 실행할 수 있습니다.

사용 케이스

  1. 댓글 기능에서 "@사용자이름"을 언급하면 언급된 사용자는 그 후 이메일 알람을 받습니다.
    예를들어, '@홍길동'과 같이 한 명만 언급되었다면 동기적으로 처리하는 것이 괜찮습니다.
    하지만 열명 이상이라면, 열 개의 다른 이메일을 보내야 합니다. 외부 API를 이용하여 처리하므로 network I/O가 발생하므로
    이를 백그라운드로 처리하면 메인 프로세스에서 blocking이 생기지 않을 것입니다.
  2. 프로필 이미지 업로드 시, 썸네일 생성을 위해서는 background로 process로 처리 할 수 있습니다.

웹앱을 구축 할 때 요청과 응답의 시간은 통상 500ms미만인지 확인해야 합니다.
New Relic이나 Scout과 같은 애플리케이션 성능 모니터링 도구를 사용하여 잠재적인 문제를 파악하고, Celery를 통해서 오랫동안 처리되는 프로세스를 별도로 격리하여 백그라운드 프로세스로 옮겨 처리 할 수 있습니다.

Celery vs FastAPI의 백그라운드 테스크

Starlette 에서 직접 제공되는 FastAPI의 BackgroundTasks 클래스를 활용하여 백그라운드에서 작업을
실행할 수 있다는 점은 주목할 가치가 있습니다.

from fastapi import BackgroundTasks

def send_email(email, message):
    pass

@app.get("/")
async def ping(background_tasks: BackgroundTasks):
    background_tasks.add_task(send_email, "email@address.com", "Hi!")
    return {"message": "pong!"}

그럼 언제 BackgroundTasks대신 Celery를 사용 할 까요?

"CPU intensive tasks"와 "Task queue"는 Celery를 사용하는 두 가지 다른 시나리오를 나타냅니다. 각각의 케이스가 다루는 문제와 필요성이 다릅니다:

CPU Intensive Tasks (CPU 집약적 작업)

이 경우는 백그라운드에서 무거운 계산을 수행해야 할 때 Celery를 사용하는 것이 좋습니다. 예를 들어, 비디오 인코딩, 대규모 데이터 처리, 과학적 계산 등 CPU 자원을 많이 소모하는 작업이 여기에 해당됩니다. 이러한 작업은 애플리케이션의 메인 이벤트 루프나 메인 스레드에서 처리할 경우 애플리케이션의 반응성과 성능에 부정적인 영향을 줄 수 있습니다. 따라서, 이러한 작업을 별도의 백그라운드 프로세스나 워커로 분리하여 처리함으로써, 애플리케이션의 메인 이벤트 루프가 사용자 요청에 더 빠르고 효율적으로 반응할 수 있도록 합니다.

Task Queue (태스크 큐)

태스크 큐 사용 시나리오는 작업의 실행을 조정하고 관리할 필요가 있을 때 적합합니다. 이는 단순히 CPU 집약적인 작업뿐만 아니라, 이메일 전송, 정기적인 데이터베이스 정리, 사용자 알림 발송 등 다양한 종류의 백그라운드 작업을 포함할 수 있습니다. 태스크 큐를 사용하면 작업을 비동기적으로 실행할 수 있을 뿐만 아니라, 작업의 상태를 추적하고, 성공 또는 실패 시 특정 액션을 취할 수 있는 등의 복잡한 워크플로우를 구현할 수 있습니다. 예를 들어, 작업이 실패했을 때 재시도 로직을 구현하거나, 작업 완료 후 사용자에게 알림을 보내는 등의 처리가 가능합니다.

요약하면

  • CPU Intensive Tasks : CPU 자원을 많이 사용하는 작업을 백그라운드에서 처리하기 위해 Celery를 사용합니다. 이는 애플리케이션의 성능을 유지하면서 무거운 작업을 효과적으로 처리하기 위함입니다.
  • Task Queue : 복잡한 작업 흐름과 상태 관리가 필요한 경우에 Celery를 사용합니다. 태스크 큐는 작업의 실행을 조정하고, 성공/실패에 따른 후속 처리를 가능하게 합니다.

두 시나리오 모두 Celery를 사용함으로써 애플리케이션의 성능과 사용자 경험을 개선할 수 있지만, 각각의 사용 사례에 따라 구체적인 이유와 방식이 다릅니다.


메시지 브러커 and Result backend

  • 메시지 브로커 : 작업을 생성하거나 소비하기 위한 전송으로 사용되는 중개 프로그램입니다
  • Result backend : Celery task 결과를 저장하는데 사용됩니다.

Celery client는 메시지 브로커를 통해 대기열에 새 작업을 추가하는 생산자입니다.
Celery woker는 메시지 브로커를 통해 대기열의 새 작업을 사용합니다. 처리된 결과는 Result backend에 저장됩니다.