Python 비동기 작업 큐 구현 - Celery와 Redis 조합

문제 상황

사용자가 프로필 이미지를 업로드하면 3가지 사이즈(썸네일, 중간, 원본)로 리사이징하는 API가 있었다. 동기 처리 방식이라 응답 시간이 평균 4~5초가 걸렸고, 이미지 크기가 클 경우 타임아웃이 발생했다.

Celery 도입

Celery는 Python의 분산 작업 큐 라이브러리다. Redis를 메시지 브로커로 사용했다.

# celery_app.py
from celery import Celery

app = Celery('tasks', broker='redis://localhost:6379/0')

@app.task
def resize_images(image_path, user_id):
    from PIL import Image
    sizes = [(150, 150), (500, 500), (1920, 1920)]
    
    for size in sizes:
        img = Image.open(image_path)
        img.thumbnail(size)
        img.save(f"{user_id}_{size[0]}.jpg")

API에서는 작업을 큐에 넣고 즉시 응답한다.

# api.py
@app.route('/upload', methods=['POST'])
def upload_image():
    file = request.files['image']
    path = save_temp_file(file)
    
    # 비동기 작업 등록
    resize_images.delay(path, current_user.id)
    
    return {"status": "processing"}, 202

결과

API 응답 시간이 평균 400ms로 단축되었다. Worker 프로세스는 별도 서버에서 실행하며, 트래픽이 많을 때는 worker 수를 늘려 확장할 수 있다.

celery -A celery_app worker --loglevel=info --concurrency=4

작업 실패 시 재시도 로직과 모니터링은 Flower를 사용해 구성했다. 재택근무 전환 시점에서 인프라 안정성이 중요해졌는데, 이 구조가 도움이 되었다.

Python 비동기 작업 큐 구현 - Celery와 Redis 조합