본문 바로가기
Django

[Django] Celery Redis 설치

by 이농이능 2018. 1. 30.


Celery 란?


비동기적으로 처리해야할 일들을 수행하기 위해 Celery를 설치했다. 실시간 서비스를 제공하기 위해 꼭 필요한 작업이다.

Celery는 비동기적으로 작업을 처리하고 응답을 하게 해주는 파이썬 프레임워크이다. 이런 프레임워크를 works라고 부른다.


celery-beat

사용자의 요청이 시간이 오래 걸리는 경우나 다른 시스템과 연동되어 그 시스템에서 응답이 올때까지 대기해야 되는 경우에 주로 사용하게 된다. 이 외에도 주기적으로 어떤 통계를 도출해 낸단더지 하는 배치(일괄 처리)작업이 필요한 경우가 종종 생기는데 이때 Celery를 이용할 수 있다. 작업큐에 주기적으로 필요한 작업들을 넣어주면 되는데 이 역할을 하는것이 Celery에 포함된 beat이다.


broker

celery 작업을 하기 위해서는 브로커를 설정한다. 브로커는 워커인 celery를 사용하기 위해서 작업 요청을 받는 큐라고 할 수 있는데 요청을 받아서 worker에게 적절히 분배하는 작업을 수행한다.



** 설치와 실행을 해보기 위해서 많은 자료를 찾아가며 했는데 이를 정리해보고자 한다. 
OS는 centos7 이고. Django와 virtualenv 가 설치되어있다는 전제하에 작성하였다. 
Django 설치 후 프로젝트와 app도 생성해놓도록 하자.


1. Celery와 Redis 설치 


pip를 이용해 cerlry 모듈과 redis와의 연동을 위한 dependency를 한 번에 설치한다. redis를 설치하지 않아도 일단 의존성 패키지는 설치 된다. 작은 따옴표('')를 꼭 붙여줘야 설치가 된다.



pip install 'celery[redis]'


1
2
3
4
$ wget http://download.redis.io/redis-stable.tar.gz
$ tar xvzf redis-stable.tar.gz
$ cd redis-stable
$ make
cs


make, make test, make install 을 실행


*** make test를 하던 중,


1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ make test
 
cd src && make test
 
make[1]: Entering directory `/home/inyoung/redis-stable/src'
You need tcl 8.5 or newer in order to run the Redis test
make[1]: *** [test] 오류 1
make[1]: Leaving directory `/home/inyoung/redis-stable/src'
 
 
make: *** [test] 오류 2
cs


You need tcl 8.5 or newer in order to run the Redis test 라는 오류가 발생 -> tcl을 설치해주었다.


$ yum -y install tcl



그리고 나서 make, make test, make install 해주면  설치 끝!





2. redis 잘 설치되어있는지 확인


  • redis-server  # server 켜진 상태

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ redis-server
3780:C 31 Jan 11:22:49.406 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3780:C 31 Jan 11:22:49.406 # Redis version=4.0.7, bits=64, commit=00000000, modified=0, pid=3780, just started
3780:C 31 Jan 11:22:49.406 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
3780:M 31 Jan 11:22:49.407 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.
3780:M 31 Jan 11:22:49.407 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted.
3780:M 31 Jan 11:22:49.407 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.7 (00000000/064 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 3780
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               
 
3780:M 31 Jan 11:22:49.409 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
 
cs



* redis-server가 켜진 상태에서, 


redis-cli ping   # ping 했을 때 PONG 찍히면 성공


$ redis-cli ping
PONG




3. Django project에 celery와 redis를 추가



1. Celery와 Redis를 virtualenv 에 설치


1
2
3
4
 pip install celery
 pip install redis
 pip install django-celery-beat
 pip install django-celery-results
cs





2. Django 프로젝트의 settings.py 수정


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_celery_beat',
    'django_celery_results',
    'scraper',
]
 
 
# Celery
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TAST_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Seoul' #Celery beat가 스케줄러이기 때문에 시간에 대한 정의를 해야함
cs



3. Celery App을 설정하기 위해서 celery.py 를 생성한다. 

** 프로젝트 설정하는 폴더에 생성해야함. settings.py가 있는 [프로젝트명] - [프로젝트명] 폴더


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from __future__ import absolute_import
 
import os
 
from celery import Celery
 
# Django의 세팅 모듈을 Celery의 기본으로 사용하도록 등록합니다.
os.environ.setdefault('DJANGO_SETTINGS_MODULE''inyoung_scrap_prj.settings')
 
app = Celery('inyoung_scrap_prj')
 
 
# 문자열로 등록한 이유는 Celery Worker가 자식 프로세스에게 configuration object를 직렬화하지 않아도 된다는것 때문
# namespace = 'CELERY'는 모든 celery 관련한 configuration key가 'CELERY_' 로 시작해야함을 의미함
app.config_from_object('django.conf:settings', namespace = 'CELERY')
 
# task 모듈을 모든 등록된 Django App configs에서 load 함
app.autodiscover_tasks()
 
 
@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))
cs



4. 프로젝트의 __init__.py를 수정한다


1
2
3
4
from __future__ import absolute_import
 
# Django가 시작할 때  shared_task가 이 앱을 이용할 수 있도록 app이 항상 import 되게 해준다. 
from .celery import app as celery_app  # noqa
cs




5. Django 프로젝트 안에 있는 app 폴더내부에 tasks.py를 생성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from __future__ import absolute_import, unicode_literals
import random
from celery.decorators import task
 
 
@task(name="sum_two_numbers")
def add(x, y):
    return x + y
 
@task(name="multiply_two_numbers")
def mul(x, y):
    total = x * (y * random.randint(3100))
    return total
 
@task(name="sum_list_numbers")
def xsum(numbers):
    return sum(numbers)
cs


6. migrations를 한다.

1
2
python manage.py makemigrations
python manage.py migrate
cs





4. 실행하기

Celery 서버를 실행해보자

celery -A   [파일이름]   worker -l info


** 오류 발생

[2018-01-30 07:56:45,445: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.

Trying again in 2.00 seconds...



--> 매우 간단한 문제였다. redis-server 가 켜져있는 상태에서 celery를 실행해야 함!




Schedule 을 작성해서 task를 실행


** crontab은 배치 작업을 위해서 특정 시간 뿐만 아니라 특정 요일과 같은 다양한 단위시간 설정을 지원한다. celery에는 이를 사용할 수 있는 모듈을 포함하고 있다. celery.schedules.crontab을 import 하여 사용할 수 있다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from celery.schedules import crontab
 
@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))
 
app.conf.beat_schedule = {
    'add-every-minute-contrab': {
        'task''multiply_two_numbers',
        'schedule': crontab(), # 1분마다
        'args': (1616),
    },
    'add-every-5-seconds': {
        'task''multiply_two_numbers',
        'schedule'5.0, # 5초마다
        'args': (1616)
    },
    'add-every-30-seconds': {
        'task''tasks.add',
        'schedule'30.0, # 30초마다
        'args': (1616)
    },
}
cs



tasks를 Celery Beat를 통해서 test 해본다.


1
celery -A [프로젝트명] beat -l info
cs






설치 및 실행해보기까지 해보았다. 이제 자기의 프로젝트에 맞게 수정해서 실행하기만 하면 된다.


- 모든 과정 -


python manage.py runserver

redis-server


-- 프로젝트가 있는 폴더에서,

celery -A [프로젝트명] worker -l info

celery -A [프로젝트명] beat -l info





출처 : 


http://docs.celeryproject.org/en/master/getting-started/first-steps-with-celery.html

https://medium.com/sunhyoups-story/celery-b96eb337b9cf

http://blog.naver.com/PostView.nhn?blogId=c_ist82&logNo=220777624611

http://whatisthenext.tistory.com/127

http://sarc.io/index.php/nosql/63-redis-2-8-6

http://yakolla.tistory.com/41

https://www.codingforentrepreneurs.com/blog/celery-redis-django/

'Django' 카테고리의 다른 글

django paginator 페이지 수 제한하기  (0) 2018.02.20
[django celery]테스크 주기 설정하기  (1) 2018.02.02
python 파일 존재여부  (0) 2018.01.29
csrf 및 form 구현  (0) 2018.01.25
[Django] 테이블 paginator  (0) 2018.01.22