【分布式异步任务框架Celery】

1 Celery介绍

1.1 Celery 是什么?

# 1 celery 是一个灵活且可靠的,处理大量消息的分布式系统,可以在多个节点之间处理某个任务

# 2 celery 是一个专注于实时处理的任务队列,支持任务调度

# 3 celery 是开源的,有很多的使用者

# 4 celery 完全基于 Python 语言编写

# 5 所以 celery 本质上是一个分布式的异步任务调度框架,类似于 Apache 的 airflow

# 6 celery 只是用来调度任务的,但它本身并不具备存储任务的功能,而调度任务的时候肯定是要把任务存起来的。因此要使用 celery 的话,还需要搭配一些具备存储、访问功能的工具,比如:消息队列、Redis缓存、数据库等等。官方推荐的是消息队列 RabbitMQ,我们使用 Redis 

1.2 celery 使用场景

# 1 异步任务
	-一些耗时的操作可以交给celery异步执行,而不用等着程序处理完才知道结果。
    -视频转码、邮件发送、消息推送等等
# 2 定时任务
	-定时推送消息、定时爬取数据、定时统计数据等

# 3 延迟任务
	-提交任务后,等待一段时间再执行某个任务

1.3 Celery官网

# 1 开源地址(源码)
https://github.com/celery/celery
    
# 2  官网
https://docs.celeryq.dev/en/stable/
    
# 4 最新版本
Celery (5.3)

# 5 python支持
Celery version 5.3 runs on
Python ❨3.8, 3.9, 3.10, 3.11# 6 Django支持
Celery 5.3.x supports Django 2.2 LTS or newer versions. Please use Celery 5.2.x for versions older than Django 2.2 or Celery 4.4.x if your Django version is older than 1.11

1.4 Celery架构

# Celery 架构,它采用典型的生产者-消费者模式,主要由以下部分组成:

# 1 Celery Beat,任务调度器,Beat 进程会读取配置文件的内容,周期性地将配置中到期需要执行的任务发送给任务队列。

# 2 Producer:需要在队列中进行的任务,一般由用户、触发器或其他操作将任务入队,然后交由 workers 进行处理。调用了 Celery 提供的 API、函数或者装饰器而产生任务并交给任务队列处理的都是任务生产者。

# 3 Broker,即消息中间件,在这指任务队列本身,Celery 扮演生产者和消费者的角色,brokers 就是生产者和消费者存放/获取产品的地方(队列)。

# 4 Celery Worker,执行任务的消费者,从队列中取出任务并执行。通常会在多台服务器运行多个消费者来提高执行效率。

# 5 Result Backend:任务处理完后保存状态信息和结果,以供查询。Celery 默认已支持 Redis、RabbitMQ、MongoDB、Django ORM、SQLAlchemy 等方式。



实际应用中,用户从 Web 前端发起一个请求,我们只需要将请求所要处理的任务丢入任务队列 broker 中,由空闲的 worker 去处理任务即可,处理的结果会暂存在后台数据库 backend 中。我们可以在一台机器或多台机器上同时起多个 worker 进程来实现分布式地并行处理任务。

在这里插入图片描述

2 Celery 快速使用

2.1 安装

# 0 创建Python项目

# 1 创建虚拟环境

# 2 安装celery
pip install celery

# 3 安装redis(消息队列和结果存储使用redis)
pip install redis

# 4 安装eventlet(win 平台)
pip install eventlet

2.2 快速使用

celery_demo.py–主文件

from celery import Celery
import time

broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery('celery_test', broker=broker, backend=backend)


@app.task
def add(n, m):
    time.sleep(2)
    print('n+m的结果:%s' % (n + m))
    return n + m


@app.task
def send_email(mail='616564099@qq.com'):
    print('模拟发送延迟--开始')
    time.sleep(2)
    print('模拟发送延迟--结束')
    return '邮件发送成功:%s' % mail

add_task.py–提交异步任务

from celery_demo import add,send_email


##1 同步调用
res=send_email()
print(res)

# 2 异步调用
res = add.delay(10, 20)
print(res.id)

通过resp查看任务

在这里插入图片描述

开启worker

celery -A celery_demo worker -l info -P eventlet

在这里插入图片描述

get_result.py-查看结果

from celery_demo import app

from celery.result import AsyncResult

id = 'd0ae78c8-9a8e-4f93-9d32-b17d4e295fe9'
if __name__ == '__main__':
    result = AsyncResult(id=id, app=app)
    if result.successful():
        result = result.get()
        print(result)
    elif result.failed():
        print('任务失败')
    elif result.status == 'PENDING':
        print('任务等待中被执行')
    elif result.status == 'RETRY':
        print('任务异常后正在重试')
    elif result.status == 'STARTED':
        print('任务已经开始被执行')

3 包结构

3.1 目录结构

项目名
    ├── celery_task  	# celery包
    │   ├── __init__.py # 包文件
    │   ├── celery.py   # celery连接和配置相关文件,且名字必须叫celery.py
    │   └── tasks.py    # 所有任务函数
    ├── add_task.py  	# 添加任务
    └── get_result.py   # 获取结果

celery.py

from celery import Celery
broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery(broker=broker, backend=backend, include=['celery_task.tasks'])

tasks.py

from .celery import app
import time
@app.task
def add(n, m):
    time.sleep(2)
    print('n+m的结果:%s' % (n + m))
    return n + m


@app.task
def send_email(mail='616564099@qq.com'):
    print('模拟发送延迟--开始')
    time.sleep(2)
    print('模拟发送延迟--结束')
    return '邮件发送成功:%s' % mail

4 执行异步–延迟–定时任务

4.1 异步任务

res = add.delay(10, 20)

4.2 延迟任务

from datetime import datetime, timedelta
eta=datetime.utcnow() + timedelta(seconds=10)
tasks.add.apply_async(args=(200, 50), eta=eta)

4.3 定时任务

#1  celery.py中加入
# 时区
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False

# 任务的定时配置
from datetime import timedelta
from celery.schedules import crontab
app.conf.beat_schedule = {
    'low-task': {
        'task': 'celery_task.tasks.add',
        'schedule': timedelta(seconds=3),
        # 'schedule': crontab(hour=8, day_of_week=1),  # 每周一早八点
        'args': (300, 150),
    }
}

# 2 启动worker
celery -A celery_task worker -l debug -P eventlet

# 3 启动beat
celery -A celery_task beat -l debug

5 Django中集成方式一(通用方案)

5.1 把上面的包-复制到djagno项目中

在这里插入图片描述

5.2 在views中编写视图函数

5.3 配置路由

5.4 浏览器访问,提交任务

5.5 启动worker执行任务

5.6 查看任务结果


6 Django中集成方式二(官方方案)

6.0 安装模块

pip installDjango==3.2.22
pip install celery
pip install redis
pip install eventlet  #在windows环境下需要安装eventlet包
-----------
pip install django-celery-beat
pip install django-celery-results
pip install django-simpleui

6.1 在项目目录下新建celery.py

import os
import django
from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'celery_demo.settings')
django.setup()
# broker = 'redis://127.0.0.1:6379/1'
# backend = 'redis://127.0.0.1:6379/2'
# app = Celery('celery_demo',broker=broker, backend=backend)


app = Celery('celery_demo')
# app.conf.update(
#     BROKER_URL='redis://127.0.0.1:6379/1',
#     # BACKEND配置,使用redis
#     CELERY_RESULT_BACKEND='redis://127.0.0.1:6379/2',
#     CELERY_ACCEPT_CONTENT=['json'],
#     CELERY_TASK_SERIALIZER='json',
#     # 结果序列化方案
#     CELERY_RESULT_SERIALIZER='json',
#     # 任务结果过期时间,秒
#     CELERY_TASK_RESULT_EXPIRES=60 * 60 * 24,
#     # 时区配置
#     CELERY_TIMEZONE='Asia/Shanghai',
# )

app.config_from_object('django.conf:settings')

app.autodiscover_tasks()
# app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)


在这里插入图片描述

6.2 在django配置文件中加入

# celery 配置
###----Celery redis 配置-----###
# Broker配置,使用Redis作为消息中间件
BROKER_URL = 'redis://127.0.0.1:6379/1'
# BACKEND配置,使用redis
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/2'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
# 结果序列化方案
CELERY_RESULT_SERIALIZER = 'json'
# 任务结果过期时间,秒
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24
# 时区配置
CELERY_TIMEZONE = 'Asia/Shanghai'

在这里插入图片描述

6.3 在主目录的__init__.py中添加如下代码

from .celery import app as celery_app

__all__ = ('celery_app',)

在这里插入图片描述

6.4 在app下新建tasks.py(必须叫tasks.py)

from celery import shared_task
import time


@shared_task()
def add():
    time.sleep(1)
    print('结果是')
    return 10


@shared_task()
def send_email(mail):
    time.sleep(1)
    print(f'给{mail}发送邮件了')
    return '成功'

在这里插入图片描述

6.5 实现异步views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

from .tasks import add
def celery_add(request):
    res=add.delay()
    return HttpResponse(res)

在这里插入图片描述

6.6 配置路由

总路由urls.py

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include('app01.urls')),
]

app自己的路由urls.py

from django.contrib import admin
from django.urls import path
from .views import celery_add

urlpatterns = [
    path('celery_demo/', celery_add),
]

6.7 启动celery

celery -A celery_demo worker -l debug -P eventlet

在这里插入图片描述

6.8 浏览器访问-添加任务

http://127.0.0.1:8000/app01/celery_demo/

7 实现定时任务

7.1 settings.py加入

# celery_beat
CELERYBEAT_SCHEDULE = {
    'every_5_seconds': {
        # 任务路径
        'task': 'app01.tasks.add',
        # 每5秒执行一次
        'schedule': 200,
        'args': ()
    },
    # 'every_10_seconds': {
    #     # 任务路径
    #     'task': 'app01.tasks.send_email',
    #     # 每10秒执行一次,task1的参数是5
    #     'schedule': 10,
    #     'args': (['306334678@qq.com'])
    # }
}

7.2 启动worker和beat

celery -A celery_demo worker -l debug -P eventlet
celery -A celery_demo beat -l debug

8 通过Admin配置定时任务

通过settings.py的配置可以实现定时任务的配置,做为实际项目中可能还是不够实用,更加工程化的做法是将定时任务的配置放到数据库里通过界面来配置。
Celery对此也提供了很好的支持,这需要安装django-celery-beat插件

8.1 安装djiango-celery-beat

pip install django-celery-beat

8.2 在APP中注册djiango-celery-beat

INSTALLED_APPS = [
....
'django_celery_beat',
]

8.3 在settings.py中设置调度器及时区

在settings.py中屏蔽到原来的调度器,加入

CELERYBEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' 

8.4 设置时区

LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False

8.5 数据库迁移

python manage.py migrate django_celery_beat

8.6 启动woker和beat

#在两个控制台分别启动woker和beta

celery -A celery_demo worker -l debug -P eventlet
celery -A celery_demo beat -l debug

8.7 创建超级用户-访问admin的web管理端

# 1 创建超级用户
python manage.py createsuperuser

# 2 访问admin
http://127.0.0.1:8000/admin/login/

8.8 美化admin

# 1 开源地址
https://gitee.com/tompeppa/simpleui
# 2 文档地址
https://newpanjing.github.io/simpleui_docs/config.html
    
# 3 安装
pip3 install django-simpleui

# 4 配置app
  INSTALLED_APPS = [
      'simpleui',
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      ...
  ]
    
# 5 重新打开admin

在这里插入图片描述

9 admin监控任务执行情况

在控制台监控任务执行情况,还不是很方便,最好是能够通过web界面看到任务的执行情况,如有多少任务在执行,有多少任务执行失败了等。
这个Celery也是可以做到了,就是将任务执行结果写到数据库中,通过web界面显示出来。
这里要用到django-celery-results插件。
通过插件可以使用Django的orm作为结果存储,这样的好处在于我们可以直接通过django的数据查看到任务状态,同时为可以制定更多的操作

9.1 安装django-celery-results

pip install django-celery-results

9.2 配置settings.py,注册app

INSTALLED_APPS = (
...,
'django_celery_results',
)

9.3 修改backend配置,将Redis改为django-db

# BACKEND配置,使用redis
#CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'

# 使用使用django orm 作为结果存储
CELERY_RESULT_BACKEND = 'django-db'  #使用django orm 作为结果存储

9.4 迁移数据库

python manage.py migrate django_celery_results
# 可以看到创建了django_celery_results相关的表

9.5 admin 查看

在这里插入图片描述

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无敌开心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值