40.Celery介绍、部署、集成到Django中(异步任务)

388 阅读3分钟

什么是 Celery?

docs.celeryq.dev/en/stable/g…

Celery是一种简单、灵活、可靠的分布式系统,可以处理大量的消息,同时提供维护这种系统所需的工具

它是一个侧重于实时处理的任务队列,同时也支持任务调度。

Celery通过消息进行通信,通常使用代理在客户和工人之间进行调解。 为了启动一个任务,客户机向队列添加一条消息,然后代理将该消息传递给工作者。

核心概念

image.png

Task: 一个需要执行的任务,任务通常异步执行

Period Task: 需要定时执行的任务,定时一定间隔执行,也可以使用 crontab 表达式设定执 行周期和时间点

Message Broker: 消息代理,临时存储,传输任务到工作节点的消息队列。可以用 Redis, RabbitMQ, Amazon SQS 作为消息代理。消息代理可以有多个,以保障系统的高可用。

Worker:工作节点,执行任务的进程,worker可以有多个,保障系统的高可用和扩展性

image.png Result Store: 结果存储

Scheduler/Beat: 调度器进程, Beat是定时任务调度器

大量需要使用异步任务的场景

  • 发送电子邮件,发送 IM 消息通知
  • 爬取网页, 数据分析
  • 图像、视频处理
  • 生成报告,深度学习

任务队列

  • 任务队列用作在线程或计算机之间分配工作的机制。

  • 任务队列的输入是一个称为任务的工作单元。专用的工作进程不断监视任务队列,以便执行新的工作。

工作模型

image.png

不同语言的客户端/服务器端实现

image.png

高可用

image.png

安装

python3 -m pip install -U Celery


python3 -m pip install "celery[redis,auth,msgpack]"

工程结构 添加celery

配置消息代理(redis作为后端)

wangdalei_dj/celery/tasks.py

#!coding=utf-8

from celery import Celery

# 第一个参数 是当前脚本的名称,第二个参数 是 broker 服务地址
app = Celery('tasks', backend='redis://172.31.7.188', broker='redis://172.31.7.188')

# backend 异步任务的结果存放到backend
# broker 存储任务的系统 代理是谁

@app.task
def add(x, y):
    return x + y

开启一个监听

celery -A tasks worker --loglevel=INFO

运行一个异步任务 wangdalei_dj/celery/run_task.py

#coding=utf-8

from tasks import add

result = add.delay(4, 4)
print('Is task ready: %s' % result.ready())

run_result = result.get(timeout=1)
print('task result: %s' % run_result)

image.png

celery 的web监控, Flower: Real-time Celery web-monitor

docs.celeryq.dev/en/stable/u…)

python3 -m pip install flower
celery -A tasks flower --broker=redis://@172.31.7.188:6379/0 

image.png

Django 与 Celery 集成:异步任务

docs.celeryq.dev/en/stable/d…

工作模型 Django 集成celery

image.png

主应用启动时 加载celery

wangdalei_dj/wangdalei/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',)

在主应用中配置模块 wangdalei_dj/wangdalei/celery.py

from __future__ import absolute_import, unicode_literals

import os

from celery import Celery, shared_task

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

app = Celery('wangdalei')

# 配置文件 都以CELERY作为前缀
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))

修改setting wangdalei_dj/settings/develop.py

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERYD_MAX_TASKS_PER_CHILD = 10
CELERYD_LOG_FILE = os.path.join(BASE_DIR, "logs", "celery_work.log")
CELERYBEAT_LOG_FILE = os.path.join(BASE_DIR, "logs", "celery_beat.log")

创建task异步任务 [send_dingtalk_message]

wangdalei_dj/interview/tasks.py

from __future__ import absolute_import, unicode_literals

from celery import shared_task

import logging

logger = logging.getLogger(__name__)


def send(message):
    logger.info("send_dingtalk_message: [{}]".format(message))


@shared_task
def send_dingtalk_message(message):
    send(message)

将task异步任务 [send_dingtalk_message] 关联到http 请求 响应中

image.png

启动worker程序

DJANGO_SETTINGS_MODULE=settings.develop celery --app wangdalei worker -l debug

启动web监控

DJANGO_SETTINGS_MODULE=settings.develop celery --app wangdalei flower --broker=redis://@172.31.7.188:6379/0 

在页面导出excel文件 image.png

后台监控可以看到celery的任务信息 image.png

image.png