异步任务队列Celery在Django中的使用

前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务。在同事的指引下接触了Celery这个异步任务队列框架,鉴于网上关于Celery和Django结合的文档较少,大部分也只是粗粗介绍了大概的流程,在实践过程中还是遇到了不少坑,希望记录下来帮助有需要的朋友。

一、Django中的异步请求

Django Web中从一个http请求发起,到获得响应返回html页面的流程大致如下:http请求发起 -- http handling(request解析) -- url mapping(url正则匹配找到对应的View) -- 在View中进行逻辑的处理、数据计算(包括调用Model类进行数据库的增删改查)--将数据推送到template,返回对应的template/response。

                         图1. Django架构总览

同步请求:所有逻辑处理、数据计算任务在View中处理完毕后返回response。在View处理任务时用户处于等待状态,直到页面返回结果。

异步请求:View中先返回response,再在后台处理任务。用户无需等待,可以继续浏览网站。当任务处理完成时,我们可以再告知用户。

二、关于Celery

  Celery是基于Python开发的一个分布式任务队列框架,支持使用任务队列的方式在分布的机器/进程/线程上执行任务调度。

            图2. Celery架构

  图2展示的是Celery的架构,它采用典型的生产者-消费者模式,主要由三部分组成:broker(消息队列)、workers(消费者:处理任务)、backend(存储结果)。实际应用中,用户从Web前端发起一个请求,我们只需要将请求所要处理的任务丢入任务队列broker中,由空闲的worker去处理任务即可,处理的结果会暂存在后台数据库backend中。我们可以在一台机器或多台机器上同时起多个worker进程来实现分布式地并行处理任务。

三、Django中Celery的实现

  在实际使用过程中,发现Celery在Django里的实现与其在一般.py文件中的实现还是有很大差别,Django有其特定的使用Celery的方式。这里着重介绍Celery在Django中的实现方法,简单介绍与其在一般.py文件中实现方式的差别。

  1. 建立消息队列

  首先,我们必须拥有一个broker消息队列用于发送和接收消息。Celery官网给出了多个broker的备选方案:RabbitMQ、Redis、Database(不推荐)以及其他的消息中间件。在官网的强力推荐下,我们就使用RabbitMQ作为我们的消息中间人。在Linux上安装的方式如下:

sudo apt-get install rabbitmq-server

  命令执行成功后,rabbitmq-server就已经安装好并运行在后台了。

  另外也可以通过命令rabbitmq-server -detached来在后台启动rabbitmq server以及命令rabbitmqctl stop来停止server。

  更多的命令可以参考rabbitmq官网的用户手册:https://www.rabbitmq.com/manpages.html

  2. 安装django-celery

pip install celery
pip install django-celery

  3. 配置settings.py

  首先,在Django工程的settings.py文件中加入如下配置代码:

import djcelery
djcelery.setup_loader()
BROKER_URL= 'amqp://guest@localhost//'
CELERY_RESULT_BACKEND = 'amqp://guest@localhost//'

  其中,当djcelery.setup_loader()运行时,Celery便会去查看INSTALLD_APPS下包含的所有app目录中的tasks.py文件,找到标记为task的方法,将它们注册为celery task。BROKER_URL和CELERY_RESULT_BACKEND分别指代你的Broker的代理地址以及Backend(result store)数据存储地址。在Django中如果没有设置backend,会使用其默认的后台数据库用来存储数据。注意,此处backend的设置是通过关键字CELERY_RESULT_BACKEND来配置,与一般的.py文件中实现celery的backend设置方式有所不同。一般的.py中是直接通过设置backend关键字来配置,如下所示:

app = Celery('tasks', backend='amqp://guest@localhost//', broker='amqp://guest@localhost//')

  然后,在INSTALLED_APPS中加入djcelery:

 

INSTALLED_APPS = (
    ……   
    'qv',
    'djcelery'
    ……   
)   

  4. 在要使用该任务队列的app根目录下(比如qv),建立tasks.py,比如:

  在tasks.py中我们就可以编码实现我们需要执行的任务逻辑,在开始处import task,然后在要执行的任务方法开头用上装饰器@task。需要注意的是,与一般的.py中实现celery不同,tasks.py必须建在各app的根目录下,且不能随意命名。

  5. 生产任务

  在需要执行该任务的View中,通过build_job.delay的方式来创建任务,并送入消息队列。比如:

  6. 启动worker的命令

#先启动服务器
python manage.py runserver
#再启动worker 
python manage.py celery worker -c 4 --loglevel=info

四、补充

  Django下要查看其他celery的命令,包括参数配置、启动多worker进程的方式都可以通过python manage.py celery --help来查看:

   另外,Celery提供了一个工具flower,将各个任务的执行情况、各个worker的健康状态进行监控并以可视化的方式展现,如下图所示:

  Django下实现的方式如下: 

  1. 安装flower:

pip install flower

  2. 启动flower(默认会启动一个webserver,端口为5555):

python manage.py celery flower

  3. 进入http://localhost:5555即可查看。

原文章地址:https://www.cnblogs.com/znicy/p/5626040.html

 

# ------------------------------------------------------------------------------------------------------------------------

另一篇,借鉴理解:

 

1. Django 处理 Request 的基本流程

Django 流程示意图

 

上面的这一张是网络上的 Django 处理 request 的流程示意图。大致意思就是:

浏览器发起 http 请求 ----> http handling(request 解析) ----> url 匹配(正则匹配找到对应的 View) ----> 在View中进行逻辑的处理与数据计算(包括调用 Model 类进行数据库的增删改查)----> 将数据推送到 template,返回对应的 template/response。

对于一些简单的操作,可以放在 View 中处理。在View处理任务时用户处于等待状态,直到页面返回结果。但是对于一些复杂的操作,则在 View 中应该先返回 response,再在后台处理任务。用户无需等待。当任务处理完成时,我们可以再通过 Ajax 之类的方式告知用户。

Celery 就是基于 Python 开发的一个分布式任务队列框架,支持使用任务队列的方式在分布的机器/进程/线程上执行任务调度。

2. Celery

Celery 的基本架构

上图是 Celery 的基本架构,它采用典型的生产生--消费者模式,主要由三部分组成:broker(消息队列)、workers(消费者:处理任务)、backend(存储结果)。实际应用中,用户从 Web 前端发起一个请求,我们只需要将请求所要处理的任务丢入任务队列 broker 中,由空闲的 worker 去处理任务即可,处理的结果会暂存在后台数据库 backend 中。我们可以在一台机器或多台机器上同时起多个 worker 进程来实现分布式地并行处理任务。

3. 安装 Celery

安装过程就是直接按照官网上的文档安装即可。我这里用的均是目前的最新稳定版。

  • macOS Sierra 10.12.3
  • Django 1.10
  • Celery 4.0.2

在早前版本的 Celery 中,有一个专门供 Django 使用的 Celery 版本:django-celery。但是在现在 Celery 已经统一为一个版本,所以直接安装原生的 Celery 即可:

 

pip install celery

Celery 推荐使用 RabbitMQRedis,Amazon SQS,Zookeeper,这几个作为 broker,但是只有前两个支持在生产环境使用。下面的表格对比了几种 broker。

NameStatusMonitoringRemote Control
RabbitMQStableYesYes
RedisStableYesYes
Amazon SQSStableNoNo
ZookeeperExperimentalNoNo

我是使用 Redis 作为 broker 的。除了安装 redis 之外,还应该安装 redis 的 python 支持库。

安装 Redis:

 

brew install redis

安装 redis 的 python 支持库:

 

pip install redis

输入 redis-server 来开启 redis。当你看见下面的图案时,就说明成功开启了 redis。redis 默认监听 6379 端口。开启之后可以用 ctrl+c 来退出。

开启 redis

4. 把 Celery 配置到 Django 上

假设你有一个项目 proj:

 

- proj/
  - proj/__init__.py
  - proj/settings.py
  - proj/urls.py
- manage.py

Celery 建议在 proj/proj/celery.py 上定义一个 Celery 的实例。

文件 proj/proj/celery.py:

 

from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

app = Celery('proj')

# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()


@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

然后再在proj/proj/__init__.py做一些配置。

文件 proj/proj/__init__.py:

 

from __future__ import absolute_import, unicode_literals

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

__all__ = ['celery_app']

完成上面的步骤之后,可以在命令行输入:

 

celery worker -A proj -l info

正常情况下,应该会出现类似于下图的输出。

开启 celery 并与 redis 连接

ok,接下来,为了让 celery 中执行的任务的结果返回我们的 Django,我们还应该安装 django-celery-results

 

pip install django-celery-results

再在 proj/proj/settings.py: 中做如下的设置:

文件proj/proj/settings.py:

 

# Celery 设置
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_BACKEND = 'django-db'
CELERY_TIMEZONE = 'Asia/Shanghai' 

INSTALLED_APPS = [
    ...
    ...
    'django_celery_results'
]

再 migrate 一下:

 

migrate django_celery_results

5. 加入一个耗时任务

在你的 app 的目录下,新建一个 tasks.py 文件。在里面加入一个耗时的任务:

 

from __future__ import absolute_import, unicode_literals
from celery import shared_task

# 模拟一个耗时操作
@shared_task
def longtime_test():
   ...
  # 在这里进行一些耗时操作
   ...

views.py 中,写成这样:

 

def test_view(request):
    # do something
    longtime_test.delay()
    return render(request, 'template.html', {'data': data})

这样之后,就会先返回 html 模版,再在后台计算数据了。



作者:柴柴土
链接:https://www.jianshu.com/p/6f8576a37a3e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值