[django] 비동기 큐 작업에 대하여 알아보자! (celery)

Gyeong Jun Paik
8 min readJun 16, 2019

--

도입 배경

문의하기를 통해 Django 에서 SMTP 를 통해 메일을 전송하는데 전송이 완료될때까지 사이트가 멈췄다. 그래서 백그라운드에서 비동기 작업을 하기 위해 Celery를 R&R하여 도입하게 되었다.

도입 전후 차이

도입 전 : 문의하기를 통해 메일을 전송하면 약 8초정도 사이트가 멈춤…?

도입 후 : 부드럽게 사이트를 이용 할 수 있었다!

* 비동기의 장단점

장점: 여러 업무를 동시에 진행 할 수 있다.

단점: 실제 완료 시간은 동기로 작업할 때 보다 Delay를 갖을 수 있다. ( 처리 량에 따라 달라짐)

큐(Queue) 작업이 필요한 이유

앞에서 비동기 작업을 하면 메일을 보내면서 여러가지 일을 할 수 있지만, 동시에 대용량의 작업을 하게 되면 컴퓨팅 파워가 급감해 서비스에 방해가 될 수 있습니다. 그래서 일을 처리하기 힘든 대용량의 데이터를 큐라는 작업 공간에 임시로 보내어 대용량의 작업을 나누어 순차적(설계에 따라 각 각의 프로세스는 순차적이지 않을수도 있음)으로 처리하게 됩니다.

구조

1. django에 등록한 Task를 Message Broker로 보낸다.

2. 테스크를 Celery에서 비동기 처리한다.

?(왜 이렇게 간단해 보이지…….ㅋㅋ)

용어 개념

  • celery

웹 서비스를 하면서 응답을 받기 오래 걸리는 작업이 종종 있습니다. 그럴 경우 사용자는 응답을 받기 위해 오랜 시간을 기다려야 합니다. 보통 웹 서비스에서 응답 시간은 서비스의 생명과 직결되므로 비동기로 작업을 처리하게 넘기고 바로 응답을 하는 경우가 많습니다. celery는 그 작업을 할 수 있도록 도와주는 파이썬 프레임워크입니다. 보통 이런 프레임워크를 worker라고 부릅니다.

  • task

비동기 큐 작업을 할 프로세스입니다.

  • Message broker

메시지 브로커(message broker), 인터페이스 엔진(interface engine[1])은 송신자의 이전 메시지 프로토콜로부터의 메시지를 수신자의 이전 메시지 프로토콜로 변환하는 중간 컴퓨터 프로그램 모듈이다. 메시지 브로커들은 응용 소프트웨어가 이전에 정의해둔 메시지를 교환할 수 있는 전기통신의 요소 또는 컴퓨터 네트워크이다.[1] 메시지 브로커들은 메시지 지향 미들웨어(MOM)의 빌딩 블록이지만 일반적으로 MOM과 원격 프로시저 호출(RPC) 등의 전통적인 미들웨어를 대체하지는 않는다

queue 공간이자, Task들을 처리 및 관리하는 역할을 합니다.

  • 메세지 브로커의 종류

아마존 웹 서비스(AWS) 심플 큐 서비스(SQS)

아파치 ActiveMQ

아파치 카프카

아파치 Qpid

Celery

Enduro/X 트랜잭셔널 메시지 큐 (Transactional Message Queue, TMQ)

파이낸셜 퓨전 메시지 브로커 (사이베이스)

퓨즈 메시지 브로커 (엔터프라이즈 ActiveMQ)

IBM 앱 커넥트

IBM 웹스피어 MQ

마이크로소프트 애저 서비스 버스 (마이크로소프트)

마이크로소프트 비즈토크 서버 (마이크로소프트)

NATS (MIT 오픈 소스 라이선스: Go로 개발됨)ㅌ

오픈 메시지 큐

오라클 메시지 브로커 (오라클)

RabbitMQ (모질라 공용 허가서, 얼랭으로 개발됨)

레디스: 오픈 소스 인메모리 데이터 구조 스토어 (데이터베이스, 캐시, 메시지 브로커로 사용됨)

  • worker

유저가 다른 업무를 보는동안 보이지 않는 곳에서 task를 처리하는 착한 친구입니다.

  • flower

celery의 Log 정보를 GUI로 볼수있는 celery 의 extension tool 입니다!.

Celery Document

http://docs.celeryproject.org/en/latest/

코드 삽질기

그렇다. 5월 15일 메일 비동기 queue 작업을 시작했다!

Celery?! message borker?!

실제 서비스 도입을 위해 개념을 확실히 익혀둘 필요가 있었다.

비동기 큐 작업에 대한 개념을 빠르게 익히고, 코드에 적용했다.

pip install celery==3.1.26.post2 django-celery==3.3.0 //base

redis==2.10.6 //development

“celery[sqs]” boto==2.49.0 //productions

celery worker 등록 → pearl/celery.py 확인

#버전별로 인식하는 것이 달랐음... 후...

# celery >4.0 app.autodiscover_tasks()

# celerty <4.0 from .settings.production import BROKER_URL os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pearl.settings.production") django.setup() app.autodiscover_tasks([app_config.name for app_config in apps.get_app_configs()])

비동기 task 등록 → config/tasks.py 확인

#로그를 남김 from celery.utils.log import get_task_logger

#이것이 비동기 task from celery import shared_task

mq 변천사

sqs → rabbitmq → redis

sqs는 가격만 보고 처음에 접근을 했었다!… 하지만, Celery 버전별로 여러개의 이슈… 모니터링 지원 X 등… 여러 사태를 맛봤다… 다른 job queue를 찾아보니 rabbitmq에 대한 자료가 많았다! → 바로 적용 ->테스트 성공

신나서 반복문을 10000번 돌리고 밥 먹으러 감 → 도착 후 queue error…

https://groups.google.com/forum/#!topic/rabbitmq-users/eyVD8M80EBQ

컴퓨터의 CPU는 100%를 달렸고, 컴퓨터는 멈춰있었다….

재설치해도 변하는 건 없었음… 코드만 푸쉬해놓고 노트북을 포맷할 생각까지 함….

rabbitmq는 여전히 먹통…. 멘탈 털털 ….

좌절한 채 금요일(어머니 생신) 칼퇴….

다음날 눈을 뜨자마자 이런 생각이 들었다.

“mq가 여러 갠데 안되는것을 붙잡을 필요가 있을까?”

바로 redis 설정 실행 성공

하지만, 테스트는 테스트일 뿐… 배포가 남아있었다?!

celery version 변천사

4.3.0 → 2.xx

https://stackoverflow.com/questions/49085230/django-celery-typeerror-can-only-concatenate-tuple-not-nonetype-to-tuple

core 코드를 건들순 없지!

2.xx → 4.11

1 2 3 4 #celery 실행 명령어 python manage.py celeryd -E -l info -c 2 (구버전) celery worker -A pearl -P solo --loglevel=INFO -n worker.%%h(신버전)-현재 사용중

우리 회사에 legacy한 코드를 가져올순 없다!

4.1.1에서 3.1.26

https://stackoverflow.com/questions/47424631/celery-sqs-pycurl-error

Pycurl…. 넌 나에게 모욕감을 줬어….

jason decoder error

sqs를 이용해 봤을 때 result와 monitor 기능을 제공하지 않는다.

그래서 CELERY_RESULT= None 으로 Initatilze를 했는데…..

None은 파이썬에서 정의하지 않음을 의미하지만 json은 알 리가 없다.

그래서 json 형식으로 맞춰주기위해 CELERY_RESULT= ““ 변경

관련 데이터 중 ‘’ 도 ““로 모두 변경하였음. 그러나 이전에서 말했던 이슈 가득이라…

배포 코드 작성(EB)

YAML(celery.config, redis.config)과 shell(celery-worker.sh)문법을 사용해서 작성했다.

YAML의 약자는 “YAML은 마크업 랭귀지가 아니다” 그러니까 이게 무슨 뜻이냐면 “YAML은 마크업 랭귀지가 아니다” YAML의 약자는 “YAML은 마크업 랭귀지가 아니다” 그러니까YAML의 약자는 “YAML은 마크업 랭귀지가 아니다” 그러니까YAML의 약자는 “YAML은 마크업 랭귀지가 아니다” 그러니까YAML의 약자는 “YAML은 마크업 랭귀지가 아니다” 그러니까YAML의 약자는…………..…………..…………..…………..…………………………Infinite loop…………..…………..…………..…………..………………

YAML은 sh파일을 호출하고
sh파일은 celery의 설정에 대한 코드가 있다.

그사이에 여러 에러들이 있었지만…. 무사히 배포 성공 ….

프로젝트(localhost) 적용 방법

새로운 라이브러리 설치

서버 환경과 동일한 라이브러리 설치

pip install -r requirement.txt

정리한 라이브러리 설치

pip install -r requirement1.txt

redis설치 (version : 5.0.5)

brew install redis

redis 실행 (로컬환경에서 실행한 상태로 서버를 실행해야함.)

redis-server

celery 실행 방법 (가상환경 ON)

celery worker -A (Main app) -P solo — loglevel=INFO -n worker.%%h

--

--

Gyeong Jun Paik
Gyeong Jun Paik

Written by Gyeong Jun Paik

DevOps Engineer at idus \ Organizer at GDG golang korea

No responses yet