Python 之 Celery + Redis + Django 教程详细

第一章 Celery简介

1、Celery是什么

1、Celery是python中使用比较多的并行分布式框架
2、Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统
3、Celery专注于实时处理的异步任务队列
4、Celery同时也支持任务调度

2、Celery使用场景

celery是一个强大的分布式任务队列的异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。

  • 异步任务: 将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等
  • 定时任务: 定时执行某件事情,比如每天数据统计

3 、Celery工作流程

在这里插入图片描述

4、Celery核心组件

Celery的架构由三部分组成,消息中间件(Broker),任务执行单元(Worker)和任务执行结果存储(Result)组成。

  • 消息中间件(Broker)
    Broker负责创建任务队列,根据一些路由规则将任务分派到任务队列,然后将任务从任务队列交付给worker
  • 任务执行单元(Worker)
    Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中,运行后台作业的进程
  • 任务结果存储(Result)
    Result用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, Redis等

另外: Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis等等

其他: Celery还支持不同的并发、序列化和压缩的手段

  • 并发:prefork、eventlet、gevent、threads
  • 序列化:pickle、json、yaml、msgpack 等
  • 压缩:zlib,、bzip2

第二章 Celery安装相关软件

备注:我是在windows10环境下做的,Linux应该大同小异

1、Celery安装

pip install celery

2、其他安装

这里有个坑.win10系统启动worker报错ValueError: not enough values to unpack (expected 3, got 0),解决办法:

pip install eventlet

Django中使用的时候,报错 AttributeError: ‘str’ object has no attribute ‘items’。redis版本太高,降低版本 pip install redis==2.10.6

pip install redis==2.10.6

第三章 Celery代码实现

1、Celery基本使用方法

备注:在这里,我使用的是redis作为消息中间件

(1)目录结构
在这里插入图片描述(2)代码实现

# app.py
from task import add

if __name__ == '__main__':
    print("Start Task ...")
    result = add.delay(2, 8)
    print("result:",result)             # 存到redis之后,返回的id
    print("result_id:",result.id)       # 存到redis之后,返回的id
    print("result:", result.get())      # 方法返回值
    print("End Task ...")
    
# task.py

import time
from celery import Celery

# 实例化一个Celery
# broker = 'redis://localhost:6379/1'
# backend = 'redis://localhost:6379/2'

# 假如本地有redis,那就localhost,
# 我使用的是阿里云服务器
broker = 'redis://ip:6379/1'
backend = 'redis://ip:6379/2'


# 参数1 自动生成任务名的前缀
# 参数2 broker 是我们的redis的消息中间件
# 参数3 backend 用来存储我们的任务结果的
app = Celery('my_task', broker=broker, backend=backend)


# 加入装饰器变成异步的函数
@app.task
def add(x, y):
    print('Enter call function ...')
    time.sleep(4)
    return x + y


if __name__ == '__main__':
    # 这里生产的任务不可用,导入的模块不能包含task任务。会报错
    print("Start Task ...")
    result = add.delay(2, 8)
    print("result:", result)
    print("End Task ...")
    

(3)终端启动服务

celery -A task worker -l info -P eventlet

  • A :参数指定celery对象的位置
  • l :参数指定worker的日志级别

备注:假如出现错误,请看第二章,Celery安装相关软件

(4)服务启动后的展示
在这里插入图片描述

(5)运行代码 ,app.py

备注:不要运行task.py,会报错
在这里插入图片描述
这个时候可以看终端,看看请求
在这里插入图片描述

(6)检验这个id的值

新增检查文件 check.py
在这里插入图片描述

# check.py

from celery.result import AsyncResult
from task import app

async_result=AsyncResult(id="455d6ad7-39cc-4e94-9fa9-456ae49cdd97", app=app)

if async_result.successful():
    result = async_result.get()
    print(result)
    # result.forget() # 将结果删除
elif async_result.failed():
    print('执行失败')
elif async_result.status == 'PENDING':
    print('任务等待中被执行')
elif async_result.status == 'RETRY':
    print('任务异常后正在重试')
elif async_result.status == 'STARTED':
    print('任务已经开始被执行')

运行结果:
在这里插入图片描述

2、Celery的配置文件配置异步任务

(1)目录结构
在这里插入图片描述
(2)init.py 包初始化文件

# __init__.py 包初始化文件

from celery import Celery

app = Celery('demo')

app.config_from_object('celery_app.celeryconfig') # 通过celery 实例加载配置文件

(3)celeryconfig.py 参数配置文件

# celeryconfig.py

from datetime import timedelta
from celery.schedules import crontab

# 参数配置文件celeryconfig.py
BROKER_URL = 'redis://ip:6379/1'
CELERY_RESULT_BACKEND = 'redis://ip:6379/2'
CELERY_TIMEZONE = "Asia/shanghai" #默认UTC
CELERY_RESULT_SERIALIZER = 'msgpack'

# 导入指定的任务模块
CELERY_IMPORTS = (
    'celery_app.task1',
    'celery_app.task2',
)

# 设置定时任务
CELERYBEAT_SCHEDULE = {
    # 每过10秒执行以下task1.add的定时任务
    'task1':{
        'task': 'celery_app.task1.add',
        'schedule': timedelta(seconds=10),
        'args': (2, 8)
    },
    # 等到22点18分执行task2的multiply
    'task2': {
        'task': 'celery_app.task2.multiply',
        'schedule': crontab(hour=22, minute=20),
        'args': (4, 5)
    }
}

(4)task1.py、task2.py 任务

# task1.py

from celery_app import app

# 加入装饰器变成异步的函数
@app.task
def add(x, y):
    print('Enter call function ...')
    return x + y
    
# task2.py

from celery_app import app

@app.task
def multiply(x, y):
    print('Enter call function ...')
    return x * y

(5)result.py 根据反馈的id查询结果

from celery.result import AsyncResult
from celery_app import app

async_result=AsyncResult(id="7628bc40-16df-4eee-b22e-fc1de9911513", app=app)

if async_result.successful():
    result = async_result.get()
    print(result)
    # result.forget() # 将结果删除
elif async_result.failed():
    print('执行失败')
elif async_result.status == 'PENDING':
    print('任务等待中被执行')
elif async_result.status == 'RETRY':
    print('任务异常后正在重试')
elif async_result.status == 'STARTED':
    print('任务已经开始被执行')

(6)produce.py 执行任务

# produce.py

from celery_app.task1 import add 	# 在这里我只调用了task1

if __name__ == '__main__':
    print("Start Task ...")
    re = add.delay(7, 5)
    print(re.id)
    print(re.status)
    print(re.get())
    print("End Task ...")

(7)启动服务

celery -A celery_app worker -l info -P eventlet

(8)然后运行 produce.py 文件
在这里插入图片描述

3、Celery的定时任务

(1)上面的配置文件 celeryconfig.py 已经写了
(2)现在只需要先启动:celery -A celery_app worker -l info -P eventlet
(3)后启动:celery beat -A celery_app -l info
(4)然后观察终端,每10秒就会 发送一个请求

4、Django + Celery

(1)安装django-celery: pip install django-celery
(2)创建一个django项目:django-admin startproject django_restful
(3)创建一个app:django-admin startapp django_celery,记得在settings中注册
(4)目录结构

在这里插入图片描述
(5)在django_celery下创建任务 tasks.py

# tasks.py 耗时任务

import time
from celery.task import Task


class CourseTask(Task):
    # 任务名称
    name = 'django-celery-task'

    def run(self, *args,**kwargs):
        print('start django celery task')
        time.sleep(2)
        if not args:    # 启动定时任务时候用的
            args = (1,1)
        print(args)
        print('x-{},y-{}'.format(args[0],args[1]))
        result = sum(args)
        print(result)
        print('end django celery task ')
        return result

(6)在django_celery中新建celeryconfig.py配置文件

# celeryconfig.py celery 配置文件

from datetime import timedelta

import djcelery
djcelery.setup_loader()

# 导入指定的任务模块
CELERY_IMPORTS = (
    'django_celery.tasks',
)

# 这里指定队列为'beat_tasks'
CELERYBEAT_SCHEDULE = {
    # 每过10秒执行以下task1.add的定时任务
    'task1':{
        'task': 'django-celery-task',
        'schedule': timedelta(seconds=10),
        'options':{
            'queue': 'beat_tasks'
        }
    },
}


# 把定时任务和普通任务区分开,绑定到不同的队列中
CELERY_QUEUES = {
    'beat_tasks': {
        'exchange': 'beat_tasks',
        'exchange_type': 'direct',
        'binding_key': 'beat_tasks',
    },
    'work_queue': {
        'exchange': 'work_queue',
        'exchange_type': 'direct',
        'binding_key': 'work_queue',
    }
}

# 绑定默认队列为work_queue
CELERY_DEFAULT_QUEUE = 'work_queue'

# 有些情况可以防止死锁
CELERYD_FORCE_EXECV = True

#设置并发的worker数量
CELERYD_CONCURRENCY = 4

# 允许重试
CELERY_ACKS_LATE = True

#每个worker最多执行100个任务然后就被销毁,可以防止内存泄露(非常重要)
CELERYD_MAX_TASKS_PER_CHILD = 100

# 设置每一个任务的最大运行时间
CELERYD_TASK_TIME_LIMIT = 12 * 30

(7)导入第六步的配置到django_celery的settings.py中

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'djcelery',
    'django_celery',
]


# Celery
from django_celery.celeryconfig import *

BROKER_BACKEND = 'redis'
BROKER_URL = 'redis://ip:6379/1'				# 中间件
CELERY_RESULT_BACKEND = 'redis://ip:6379/2'	# 结果
CELERY_TIMEZONE = "Asia/shanghai" # 默认UTC

(8)在django_celery的views.py中添加执行任务函数

def do(request):
	js_str = request.body
	js_obj = json.loads(js_str)
	num1 = js_obj.get('num1',1)
	num2 = js_obj.get('num2',2)
	# 执行异步任务
	print("do request")
	re = CourseTask.delay(num1,num2)
	print(re.id,type(re.id))
	print(re.status)
	print("end do request")
	return JsonResponse({'result:': 'ok','code':re.id})

(9)配置django_celery的urls

from django.conf.urls import url
from django_celery import views

urlpatterns = [
    url('do/', views.do),
]

注意:记得配置总的django_restful的路由,

urlpatterns = [
    url(r'^django_celery/',include('django_celery.urls'))
]

(10)window下启动celery worker: python manage.py celery worker -l INFO -P eventlet

(11)启动服务器 python manage.py runserver. 输入网址:http://127.0.0.1:8000/django_celery/do/
注意:这里我建议使用postman进行测试,不知道的,百度一下,接口测试的一个软件,然后我用的是post请求

(12)设置一个定时任务在django_celery中celeryconfig.py配置文件加入

上面的配置文件,我都已经加好了

# 这里指定队列为'beat_tasks'
CELERYBEAT_SCHEDULE = {
    # 每过10秒执行以下task1.add的定时任务
    'task1':{
        'task': 'course-task',
        'schedule': timedelta(seconds=10),
        'options':{
            'queue': 'beat_tasks'
        }
    },
}

(13)启动定时任务:python manage.py celery beat -l INFO

注意:启动的顺序,启动顺序 (10)-- (11)-- (13)

5、Celery的部署和监控

(1)监控工具flower

  • 安装:

pip install flower

  • 启动Flower web控制台:

这个是在django中启动的方法 :
python manage.py celery flower

这个是在前面提到的基础使用,包文件,那样子的启动 :
celery -A celery_app flower

  • 启动后的访问地址:

127.0.0.1:5555

第四章 遇到的bug

1、celery task任务在redis存储有乱码

(1)有时候,我们在redis存完数据以后,发现乱码问题
在这里插入图片描述
在这里插入图片描述
解决办法:

方法一:

在配置文件中加入:CELERY_RESULT_SERIALIZER = ‘json’

方法二:

import pickle

print(pickle.loads(b"\x80\x02}q\x00(X\x06\x00\x00\x00statusq\x01X\a\x00\x00\x00SUCCESSq\x02X\x06\x00\x00\x00resultq\x03K\x0cX\t\x00\x00\x00tracebackq\x04NX\b\x00\x00\x00childrenq\x05]q\x06u."
))
  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Django中的Celery是一个基于Python分布式任务队列,它可以用来异步执行耗时的任务,例如发送邮件、生成PDF等等。Celery需要配合一种消息中间件来使用,而Redis是一种流行的消息中间件,可以与Celery配合使用。 在Django中使用CeleryRedis可以按照以下步骤进行: 1. 安装CeleryRedis ``` pip install celery redis ``` 2. 在Django项目中配置CeleryDjango项目的settings.py文件中添加如下配置: ``` # 配置Celery CELERY_BROKER_URL = 'redis://localhost:6379/0' # 指定redis作为消息中间件 CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' # 指定redis作为结果存储 # 加载Celery配置 CELERY_TIMEZONE = 'Asia/Shanghai' CELERY_ACCEPT_CONTENT = ['application/json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' ``` 3. 在Django项目中创建Celery任务 在Django项目的某个app中,可以创建一个tasks.py文件,定义Celery任务: ``` from celery import shared_task @shared_task def add(x, y): return x + y ``` 4. 启动Celery worker 在命令行中,进入Django项目的根目录,启动Celery worker: ``` celery -A project_name worker --loglevel=info ``` 其中,project_name是Django项目的名称。 5. 调用Celery任务 在Django项目中,可以通过如下方式调用Celery任务: ``` from .tasks import add result = add.delay(2, 3) ``` 上述代码会异步执行add任务,返回一个AsyncResult对象,可以通过该对象获取任务执行结果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值