AlgoMate

Redis만으로도 비동기 처리는 가능하잖아‼️ 근데 왜 Celery+Redis를 사용해야 할까

SungHoJung 2025. 2. 18. 00:40

FastAPI에서 비동기 작업을 위한 Redis vs Celery: 언제, 왜 사용해야 할까?

최근 웹 애플리케이션에서는 백그라운드에서 무거운 작업을 실행할 필요가 많다.
예를 들어, 크롤링, 데이터 처리, 대량의 이메일 전송, 이미지 변환 같은 작업들은 즉시 응답할 필요가 없으며, 사용자가 기다리지 않도록 백그라운드에서 실행하는 것이 필수적이다.

 

이때, Python 기반의 FastAPI와 함께 사용할  수 있는 대표적인 비동기 처리 방법이 RedisCelery이다.
Redis만 사용해도 비동기 처리가 가능하지만, Celery까지 도입하면 훨씬 강력한 기능을 활용할 수 있다.
이번 글에서는 Redis만 사용한 비동기 처리 vs Celery + Redis를 사용한 비동기 처리의 차이를 정리해보려고 한다.


1. 비동기 처리가 필요한 이유

FastAPI는 비동기(Async) 지원을 강점으로 가지지만,
CPU를 많이 사용하는 작업이나 오래 걸리는 작업(크롤링, 데이터 분석 등)은 여전히 FastAPI만으로는 해결하기 어렵습니다.

예를 들어, 사용자가 다음과 같은 요청을 보낸다고 가정해봅시다.

POST /api/scrape
{
    "problem_id": "1027",
    "language_id": "1003"
}

FastAPI에서 동기적으로 처리하면 문제점

@router.post("/scrape")
async def start_scraping(request: ScrapeRequest):
    driver = webdriver.Chrome()
    ScrapingService.fullScrapeProcess(driver, request.problem_id, request.language_id)
    driver.quit()
    return {"message": "✅ 크롤링 완료"}

 

문제점:

  • 크롤링이 끝날 때까지 사용자는 계속 기다려야 함
  • 다른 API 요청도 차단됨(동시성 문제) ❌
  • 크롤링이 실패하면 재시도 로직이 없음

해결 방법:

  • Redis를 사용하여 비동기 백그라운드 처리
  • Celery까지 추가하면 재시도, 작업 관리, 확장성까지 해결

2. Redis만 사용한 비동기 처리

Redis는 기본적으로 비동기 작업을 처리할 수 있는 두 가지 방법을 제공합니다.

1️⃣ 방법 1: FastAPI BackgroundTasks + Redis

FastAPI에서 제공하는 BackgroundTasks를 활용하면 요청을 백그라운드에서 실행할 수 있습니다.

from fastapi import FastAPI, BackgroundTasks
import redis

app = FastAPI()
redis_client = redis.Redis(host="localhost", port=6379, db=0)

def scrape_task(problem_id, language_id):
    """ ✅ Redis에 크롤링 요청 저장 """
    redis_client.rpush("scrape_queue", f"{problem_id}:{language_id}")

@app.post("/scrape")
async def start_scraping(background_tasks: BackgroundTasks, problem_id: str, language_id: str):
    """ ✅ 요청을 백그라운드에서 실행 """
    background_tasks.add_task(scrape_task, problem_id, language_id)
    return {"message": "✅ 크롤링 요청이 등록되었습니다."}

 

⏩ 실행 흐름:

  • 사용자가 /scrape 요청을 보내면, 즉시 응답을 반환
  • scrape_task()가 백그라운드에서 실행되며, Redis에 요청 저장
  • 이후 Redis에서 scrape_queue를 읽어서 크롤링 실행

장점:
    요청을 즉시 응답하고, 비동기 작업 실행 가능
    FastAPI 내부에서 처리 가능하므로 추가적인 작업자(Worker)가 필요 없음

단점:
    실패한 작업을 자동 재시도할 수 없음 
    작업의 실행 상태를 추적하기 어려움
    우선순위(Priority) 설정 불가

2️⃣ 방법 2: Redis Pub/Sub (발행-구독) 모델

Redis의 Pub/Sub 기능을 활용하면 이벤트 기반으로 비동기 작업을 실행할 수 있습니다.

 

FastAPI에서 크롤링 요청을 발행 (Publish)

@app.post("/scrape")
async def start_scraping(problem_id: str, language_id: str):
    redis_client.publish("scrape_channel", f"{problem_id}:{language_id}")
    return {"message": "✅ 크롤링 요청이 등록되었습니다."}

 

크롤링 작업을 처리하는 별도 Worker (Subscriber)

import redis

redis_client = redis.Redis(host="localhost", port=6379, db=0)
pubsub = redis_client.pubsub()
pubsub.subscribe("scrape_channel")

for message in pubsub.listen():
    if message["type"] == "message":
        data = message["data"].decode("utf-8")
        problem_id, language_id = data.split(":")
        print(f"🚀 크롤링 실행: 문제 {problem_id}, 언어 {language_id}")

 

 

이제 FastAPI에서 요청을 보내면, Worker가 자동으로 크롤링을 실행한다.

장점:
     비동기 이벤트 기반 실행 가능
     여러 개의 Worker가 확장 가능

단점:
    작업 실패 시 재시도 불가
    작업 결과를 저장하는 기능 없음
    우선순위 관리 불가

3. Celery + Redis를 사용한 비동기 처리 (더 강력한 기능 제공)

Celery는 Redis만 사용했을 때의 한계를 보완하는 기능을 제공한다.

기능 Redis만 사용 Celery + Redis
비동기 실행 가능 ✅ 가능 ✅
자동 재시도 직접 구현 필요 ❌ 자동 지원 ✅
작업 우선순위 직접 구현 ❌ 지원 ✅
작업 상태 조회 직접 Redis에 저장 ❌ 자동 결과 저장 ✅
확장성 단일 서버 제한 ❌ 여러 개의 Worker 사용 가능 ✅

Celery를 활용한 크롤링 작업

from celery_config import celery_app
from services.scraping_service import ScrapingService
from selenium import webdriver

@celery_app.task(name="scrape_baekjoon")
def scrape_baekjoon(problem_id, language_id):
    driver = webdriver.Chrome()
    ScrapingService.fullScrapeProcess(driver, problem_id, language_id)
    driver.quit()
    return {"message": "크롤링 완료"}

FastAPI 컨트롤러에서 Celery Task 실행

from workers.scraping_tasks import scrape_baekjoon

@router.post("/scrape")
async def start_scraping(request: ScrapeRequest):
    task = scrape_baekjoon.delay(request.problem_id, request.language_id)
    return {"message": "크롤링 작업이 시작되었습니다.", "task_id": task.id}

 

이제 사용자는 즉시 응답을 받고, Celery가 백그라운드에서 크롤링 실행하게 된다

결론

작업이 간단하면 Redis만 사용해도 가능하다
대량의 작업을 관리하고, 자동 재시도 및 상태 추적이 필요하면 Celery + Redis가 더 강력하다

FastAPI에서 크롤링을 비동기로 실행할 때는 Celery + Redis 조합이 가장 좋은 선택인 것 같다