celery
是一个分布式异步框架,当我们有一个需求,比如我需要进行大批量的邮箱发送,或者博客订阅推送的时候,会造成大量的等待执行,这时候就会用到celery
,
Celery 介绍
在Celery中几个基本的概念,需要先了解下,不然不知道为什么要安装下面的东西。概念:Broker、Backend。
什么是broker?
broker是一个消息传输的中间件,可以理解为一个邮箱。每当应用程序调用celery的异步任务的时候,会向broker传递消息,而后celery的worker将会取到消息,进行对于的程序执行。好吧,这个邮箱可以看成是一个消息队列。其中Broker的中文意思是 经纪人 ,其实就是一开始说的 消息队列 ,用来发送和接受消息。这个Broker有几个方案可供选择:RabbitMQ (消息队列),Redis(缓存数据库),数据库(不推荐),等等
什么是backend?
通常程序发送的消息,发完就完了,可能都不知道对方时候接受了。为此,celery实现了一个backend,用于存储这些消息以及celery执行的一些消息和结果。Backend是在Celery的配置中的一个配置项 CELERY_RESULT_BACKEND ,作用是保存结果和状态,如果你需要跟踪任务的状态,那么需要设置这一项,可以是Database backend,也可以是Cache backend,具体可以参考这里: CELERY_RESULT_BACKEND 。
对于 brokers,官方推荐是 rabbitmq 和 redis,至于 backend,就是数据库。为了简单可以都使用 redis。
我自己演示使用RabbitMQ作为Broker,用MySQL作为backend。
来一张图,这是在网上最多的一张Celery的图了,确实描述的非常好
Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。
消息中间件
Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis, MongoDB (experimental), Amazon SQS (experimental),CouchDB (experimental), SQLAlchemy (experimental),Django ORM (experimental), IronMQ
任务执行单元
Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。
任务结果存储
Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis,memcached, mongodb,SQLAlchemy, Django ORM,Apache Cassandra, IronCache 等。
一、安装
pip install celery redis
二、编写
#tasks.py
from celery import Celery
import time
app = Celery("task_transport", #任务名称,可随意填写
borker="redis://127.0.0.1:6379", #任务队列,指定从哪里调度,
backend="redis://127.0.0.1:6379" #存放结果
)
@app.task
def add(x,y):
time.sleep(15)
print('function is running')
return x + y
三、启动
celery -A task worker -l info #task为脚本名称 worker为工作模式,info输出日志到屏幕
四、测试
#终端ipython
In [1]: import celery
In [2]: import task
In [3]: s = task.add.delay(10,20) #调用add函数的delay方法传入参数
In [4]: s
Out[4]: <AsyncResult: c3e9c1d3-310f-46cf-9956-b3b897f10b7b>
In [5]: s.get() #获取返回结果
五、项目模式
#celery_project/
task2.py
celery.py
_pycache__
#celery.py
from __future__ import absolute_import,unicode_literals
from celery import Celery
app = Celery(
"project",
broker="redis://127.0.0.1:6379",
backend="redis://127.0.0.1:6379",
include=["task1","task2"]) #执行多个任务,这里对应的是当前目录的task1.py,task2.py
app.conf.update(
result_expires=3600, #任务结果一小时内没有获取则过期
)
app.config_from_object('celery_app.celeryconfig') #通过Celery实例加载配置模块
if __name__ == '__main__':
app.start()
#task1.py & task2.py
from __future__ import absolute_import,unicode_literals
from .celery import app
@app.task
def add(x,y):
return x + y
@app.task
def delete(x,y):
return x - y
#执行
celery -A celery_project worker -l info //celery_project为目录名称
#测试方法一样,开启另外一个终端调用task1或task2.py中的函数
celery常用方法
result = task.add.delay(10,20) //调用函数和delay方法
result.get() //获取结果,timeout默认为0
result.ready() //如果函数执行出现阻塞则返回False,可进行判断!
result.get(propagate=False) // 如果出错,获取错误结果,不触发异常
result.traceback //打印异常详细结果
result.id //任务id
celery multi start name project_name -l info //启动celery任务并后台运行
celery multi restart worker -A celery_project //重新启动celery任务
celery multi stop worker //停止
Celery定时任务
#task1.py
from __future__ import absolute_import,unicode_literals
from .celery import app //从主程序倒入
from celery.schedules import crontab
@app.on_after_configure.connect
def setup_periodic_tasks(sender,**kwargs):
#请注意,这里的name不能相同!必须唯一,否则执行该方法!
sender.add_periodic_task(5.0,delete.s(10,20),name="add every 10") //每五秒
sender.add_periodic_task(5.0,add.s(2,20),name="add every 10")
sender.add_periodic_task(
crontab(hour=20,minute=15), //每天20点15
add.s(200,5)
)
@app.task
def add(x,y):
return x + y
@app.task
def delete(x,y):
return x - y
#启动worker
celery -A celery_project worker -l debug
#启动beat
celery -A celery_project.task1 beat -l debug
基于配置文件方式定义执行任务
app.conf.beat_schedule = {
'add-every-30-seconds' : {
'task': 'celery_project.task1.add',
'schedule': 5.0,
'args': (100,200)
}
}
app.conf.timezone = 'UTC'
Django & Celery
pip install django-celery //安装django-celery
#需要和settings.py同级创建celery.py
#settings.py
INSTALL_APP -> djcelery //INSTALL_APP下加入djcelery
import djcelery
djcelery.setup_loader()
BROKER_URL = 'redis://127.0.0.1:6379' #队列地址
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379' #存储结果
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_IMPORTS = ('api.tasks', )
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler' #是使用了django-celery默认的数据库调度模型,任务执行周期都被存在你指定的orm数据库中
CELERYD_CONCURRENCY = 20 #worker并发数
CELERY_TASK_RESULT_EXPIRES = 1200 #任务结果过期时间
CELERYD_PREFETCH_MULTIPLIER = 4 # celery worker 每次去redis取任务的数量
CELERYD_MAX_TASKS_PER_CHILD = 200 # 每个worker执行了多少任务就会死掉,我建议数量可以大一些,比如200
#celery.py -> 与settings.py同级
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
from django.conf import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Celery_Project.settings')
app = Celery('Celery_Project')
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
#__init__.py
from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app
#{app_name}/tasks.py 可以在每一个app下创建tasks.py文件进行celery任务编写
from __future__ import absolute_import, unicode_literals
from celery import shared_task
@shared_task
def add(x, y):
return x + y
#start
python manage.py migrate djcelery //生成数据表
python manage.py runserver //启动django
python manage.py celery worker -c 6 -l debug //启动celery