KS blog

killins.egloos.com

포토로그



Celery, Distributed task queue 혹은 worker by KillinS

웹서비스에서 뒷단의 작업을 처리하는 별도의 프레임웍을 사용하는 케이스가 많은데 보통 이런 기능을 하는 프레임웍을 worker라고 많이들 부른다. 그중 파이썬으로 작성된 celery 및 worker의 간단한 개념을 정리해본다.

사실 celery를 무엇이라고 불러야할지 명확하게 잘 모르겠다. Celery 공식 홈페이지에는 Distributed task queue 라고 되어있고 실제 그러한 명칭으로 많이 불리는데, 단순히 worker라는 이름으로도 많이 부르는것 같다. 사실 Queue라는 표현은 AMQP와 같은 메시지 큐와 혼돈을 줄 수 있기 때문에 적절한 표현은 아닌것 같은것이, celery가 하는 일은 큐의 역할보다는 특정 작업의 deferred 처리를 위한 processor라고 보는것이 적절하기 때문이다. 굳이 표현하자면 distributed task processor가 옳은 표현이 아닐까 싶은데, 일단은 편의상 worker라고 불러보기로 한다.

Worker는 통상적인 웹 서비스에서 사용자에게 즉각적인 반응을 보여줄 필요가 없는 작업들로 인해 사용자가 느끼는 딜레이를 최소화하기 위해서 사용된다. 예를 들어 사진을 웹서버에 올리는 서비스가 있다고 치자. Worker는 사용자가 많을 경우 각 사용자는 사진이 서버에서 처리되고 DB에 저장되기까지 기다림으로써 서버의 응답이 느려지는 문제를 줄여주는 역할을 한다. 즉, 앞단의 웹서버는 사용자의 사진 등록 요청이 왔을 경우 일단 사용자에게 응답을 보내주고, 실제 사진을 DB에 등록하는 일은 celery와 같은 worker에게 넘겨서 처리하도록 하는 방식인것이다. (물론 사용자에게 가는 응답이 최종적인 작업을 마치지 않은 상태에서의 응답이라는 것에 대한 고려가 필요하다.) 간단하게 그림으로 표현하면 아래와 같다.

당연히 distributed라는 이름에 맞게 작업을 요청하는 웹서버와 worker는 같은 서버에 있을수도 있고 아닐수도 있다. 그리고 보통 다수의 사용자에 의한 다수의 요청을 다수의 worker를 통해서 처리하기 때문에, 쏟아져 들어오는 작업 요청을 다수의 worker에게 적절하게 분배하는 기능이 필요하고, 따라서 worker는 단독으로는 쓰이지 않고 AMQP와 같은 메시지 브로커와 함께 사용된다. 작업을 요청하는 웹서버는 요청한 작업의 결과를 받아볼 수도 있고, 그냥 요청만 던져주고 무시할 수도 있다.

Celery는 python으로 작성되었다. 그렇다고 python으로 작성된 웹서버와 함께 쓸 수 있는것만은 아니고, 루비를 위한 RCelery, Node.js를 위한 node-celery 등도 존재하며, webhook을 통해 http로 구성된 요청도 처리할 수 있어 언어에 관계 없이 사용 가능하다고 볼 수 있다.

Celery는 수행할 작업인 task 및 task의 실행을 의뢰받을브로커(AMQP, redis 등)를 정의하고, 이것들을 포함하는 app을 선언한 뒤, celery를 실행함으로써 기동된다. 간단한 코드는 다음과 같다.


# tasks.py : task 및 app 선언
from celery import Celery
app = Celery('tasks', broker='amqp://')
@app.task
def add(x,y):
  return x+y


# Celery 기동
$ celery -A tasks worekr --loglevel=info


자세한 예제 및 기타 문법은 다음 포스팅에서...