Celery + Redis的异步任务详解

一、背景

在开发过程中,有时会遇到一些需要执行时间很长的任务,如果放在前端,会让用户一直等待任务执行完或者一直转圈圈,用户体验非常不好。为了改善这种体验,使用异步的方法可以解决以上情况。在Django中,我们可以使用celery异步框架,我们可以把耗时的任务(或者定时的任务)交给后台执行,而前端给用户立即返回,待用户需要查看结果时,点击查看即可,并且可以随时看到任务执行的状态。

二、原理

Celery是基于Python开发的一个分布式任务队列框架,支持使用任务队列的方式在分布的机器/进程/线程上执行任务调度。它是Python写的库,但是它实现的通讯协议也可以使用ruby,php,javascript等调用。异步任务除了消息队列的后台执行的方式,还是一种定时计划任务。

Celery 是一个强大的分布式任务队列,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。它的架构组成如下图 :
Celery + Redis的异步任务详解_第1张图片
组件:

1、任务(tasks)–用户定义的函数,用于实现用户的功能,比如执行一个耗时很长的任务

2、中间介(Broker)–用于存放tasks的地方,但是这个中间介需要解决一个问题,就是可能需要存放非常非常多的tasks,而且要保证Worker能够从这里拿取

3、执行者(Worker)–用于执行tasks,也就是真正调用我们在tasks中定义的函数

4、存储(Backend)–把执行tasks返回的结果进行存储,以供用户查看或调用

三、实现

1、各模块功能:
Celery中,以上组件具体功能如下:

任务模块 Task

包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发(一般是在views.py中)并发往任务队列,而定时任务由 Celery Beat 进程周期性地将任务发往任务队列。

消息中间件 Broker

Broker,即为任务调度队列,接收任务,将任务存入队列。Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。

Worker用来执行任务

Worker 是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它。

任务结果存储 Backend

Backend 用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, Redis 和 MongoDB 等

2、实现步骤:
使用 Celery 实现异步任务主要包含三个步骤:

• 创建一个 Celery 实例
• 启动 Celery Worker
• 应用程序调用异步任务

3、操作流程:
a、环境安装(RabbitMQ/Redis、Celery、django-celery、flower)

b、新建文件

celery下面需要修改的文件:celery.py、init.py、settings文件

现在我们以一个实例来说明celery + redis的使用:
1、安装相关的包:
pip install celery
pip install redis
pip install eventlet
笔者在使用的是windos 7 + celery 4.4.6 + redis 3.5.3 + eventlet 0.25.2
在windos 7中安装redis。并设置登录密码:修改安装目录下的redis.windows-service.conf文件,增加:requirepass 123456,默认的密码为空。

2、配置redis,在安装的redis目录下,启动Redis:
C:\Program Files\Redis>redis-cli
127.0.0.1:6379> auth 123456 # 输入用户auth 输入密码。如果出现ok,说明redis服务正常。

3、编写celery异步任务:
在项目中(e_shop):
项目的e_shop的目录结构如下:
Celery + Redis的异步任务详解_第2张图片
(1)首先在项目e_shop的目录下,新建一个文件celery_task.py文件:

# 用来保存保存项目的 Celery 配置
import os
from django.conf import settings
from celery import Celery

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

# 创建一个实例,创建应用实例
app = Celery('e_shop',
             broker='redis://:[email protected]/0',
             backend='redis://:[email protected]/0')

# 使用 config_from_object() 方法从项目设置加载自定义配置
app.config_from_object('django.conf:settings')
# 告诉 Celery 自动发现 INSTALLED_APPS 中的应用的异步任务
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

用来保存celery配置。
(2)修改__init__.py文件:

# import celery
from .celery_task import app as celery_app

(3)在需要增加异步任务的app中增加task任务。
在orders的app中新增加一个task.py文件,用于处理任务的函数:

from celery import task
from django.core.mail import send_mail

from .models import Order


# 一个 Celery 任务只是一个使用 task 装饰的 Python 函数
@task
def order_created(order_id):
    """
    Task to send an e-mail notification when an order is
    successfully created.
    """
    order = Order.objects.get(id=order_id)
    subject = 'Order nr. {}'.format(order.id)
    message = 'Dear {},\n\nYou have successfully placed an order.\
                  Your order id is {}.'.format(order.first_name, order.id)
    #mail_sent = send_mail(subject, message, '[email protected]', [order.email])
    mail_sent = subject + message
    return mail_sent

其实celery的任务其实就是一个函数。
(4)在订单系统中完成异步任务的调用,当订单完成清空购物车后,发邮件给购买人,在订单的views.py中增加:

            cart.clear()
            # launch asynchronous task
            # 调用 delay() 方法来异步执行任务
            order_created.delay(order.id)

4、运行项目,在项目的Terminal中运行celery任务:
celery -A e_shop worker -l info -P eventlet

D:\python study\e_shop>celery -A e_shop worker -l info -P eventlet

 -------------- celery@pgos v4.4.6 (cliffs)
--- ***** -----
-- ******* ---- Windows-7-6.1.7601-SP1 2020-07-15 17:19:21
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app:         e_shop:0x44e7dc0
- ** ---------- .> transport:   redis://:**@127.0.0.1:6379/0
- ** ---------- .> results:     redis://:**@127.0.0.1/0
- *** --- * --- .> concurrency: 4 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery

5、触发任务,在订单系统中完成订单,将触发异步任务的完成。
如果执行成功,Terminal中显示:

[2020-07-15 17:19:23,039: INFO/MainProcess] celery@pgos ready.
[2020-07-15 17:20:19,046: INFO/MainProcess] Received task: orders.tasks.order_created[7f22fdb8-3bc6-491b-87c9-379524f40699]
[2020-07-15 17:20:19,331: INFO/MainProcess] Task orders.tasks.order_created[7f22fdb8-3bc6-491b-87c9-379524f40699] succeeded in 0.2809999999990396s: 'Order nr. 11Dear liu,

You have successfully placed an order.                  Your order id is 11.'

你可能感兴趣的:(python学习,python,redis,django)