Celery简要介绍
Celery是Python开发的分布式任务调度模块,是一个异步的任务队列基于分布式消息传递。Celery本身不含消息服务,它使用第三方消息服务来传递任务,目前,Celery支持的消息服务有RabbitMQ、Redis甚至是数据库,当然Redis应该是最佳选择。
使用Redis作为Broker时,再安装一个celery-with-redis。
celery(芹菜)是一个异步任务队列/基于分布式消息传递的作业队列。
它侧重于实时操作,但对调度支持也很好。
celery用于生产系统每天处理数以百万计的任务。
celery是用Python编写的,但该协议可以在任何语言实现。它也可以用其他语言通过webhooks实现。
目前已知有php/ruby/nodejs的实现
为什么用Celery?
异步
耗时久的事儿可以扔给 Worker处理,处理完可以触发子任务提醒
天然的并发能力(多进程/协程)!
非常方便添加 Worker来增强处理能力
Celery提供了Web方式的监控/报警,这样,我们就可以监控每个任务的情况了
出现错误可以自动处理/重试
角色介绍
Brokers: 提供队列服务,Celery支持的Brokers有:
RabbitMQ(推荐)
Redis
MongoDB
Beanstalk
CouchDB
SQLAlchemy(MySQL/PostgreSQL/Sqlite/Oracle)
Amazon SQS等
Worker: 真正干活的,实际运行任务的节点。
开始 Celery 的第一步
选择Broker
在你正式开始使用 Celery之前,你需要选择、安装并运行一个 broker。
Broker 是一种负责接收、发送任务消息(task messages)的服务
你可以从以下几种 broker中选择一个:
RabbitMQ :[[http://www.rabbitmq.com/]]
功能完整、安全、饱经实践检验的 broker。如果对你而言,不丢失消息非常重要,RabbitMQ将是你最好的选择。
请查看 [[/技术分享/Celery/broker-installation]]以便获得更多关于 RabbitMQ安装和配置相关的信息。
Redis :[[http://redis.io/]]
也是一个功能完整的 broker,但电源故障或异常将导致数据丢失。
请查看 [[/技术分享/Celery/otherqueues-redis]]以便配置相关的信息。
数据库
不推荐使用数据库作为消息队列,但在非常小的应用中可以使用。Celery可以使用 SQLAlchemy和 DjangoORMS。请查看 [[/技术分享/Celery/otherqueues-sqlalchemy]]或 [[/技术分享/Celery/otherqueues-django]]。
更多其他选择
除了上面列出的以外,还有其他可以选择的传输实现,例如 CouchDB,Beanstalk, MongoDB, and SQS。请查阅 Kombu的文档以便获得更多信息。
创建一个简单“任务”(Task)
from celery import Celery
app = Celery(
'myapp',
broker='amqp://guest@localhost//',
#broker='redis://localhost:6379/0',
# ## add result backend here ifneeded.
backend='amqp',
)
@app.task
def add(x, y):
return x + y
运行 worker 服务器
celery -A tasks worker --loglevel=info
执行任务(task)
>>> result = add.delay(4, 4)
这里是一些你可以如何处理结果的方法:
>>> result.ready() # 任务是否已经执行,如果已经执行完毕,返回值为 True。False
>>> result.result # 任务还没完成,尚无返回值。None
>>> result.get() # 等待,直到任务执行完毕并返回值。8
>>> result.result # 直接返回结果,不产生任何错误。8
>>> result.successful() # 任务是否成功执行,如果成功则返回值 True。True
CELERY_RESULT_BACKEND ="amqp"#: 我们希望结果最多保存 5 分钟。 #: 注意,这个特性需要 2.1.1 以上版本 RabbitMQ 才能支持。#: 如果你使用的是早期版本的 RabbitMQ,请注释下面这行。
CELERY_TASK_RESULT_EXPIRES =300
BROKER_URL = "amqp:''guest:guest@localhost :5672''" #连接 broker
CELERY_RESULT_BACKEND = "amqp" #用于存储元数据(metadata)和返回值(return values)的后端
CELERY_IMPORTS = ("tasks", ) #列出 worker 需要 import 的模块
使用Redis作为Broker时,再安装一个celery-with-redis。
开始编写tasks.py:
# tasks.py
import time
from celery
import Celery
celery = Celery(
, broker=
)
@celery.task
defsendmail(mail):
print(
% mail[
])
time.sleep(
)
print(
)
然后启动Celery处理任务:
celery -
tasks worker --loglevel=info
上面的命令行实际上启动的是Worker,如果要放到后台运行,可以扔给supervisor。
如何发送任务?非常简单:
tasks
sendmail
sendmail.delay(dict(to=
))
<AsyncResult:
a0a9262-
-
-
-b7bf0ea7483b>
可以看到,Celery的API设计真的非常简单。
然后,在Worker里就可以看到任务处理的消息:
[
-
-
:
:
,
: WARNING/MainProcess] celery
[
-
-
:
:
,
: INFO/MainProcess] consumer: Connected to redis://localhost:
/
[
-
-
:
:
,
: INFO/MainProcess] Got task
broker: tasks.sendmail[
a0a9262-
-
-
-b7bf0ea7483b]
[
-
-
:
:
,
: WARNING/PoolWorker-
] sending mail to celery
[
-
-
:
:
,
: WARNING/PoolWorker-
] mail sent.
[
-
-
:
:
,
: INFO/MainProcess] Task tasks.sendmail[
a0a9262-
-
-
-b7bf0ea7483b] succeeded
s:
要使celery找到相应的tasks有四种方法
1 在项目的celery中写tasks。如在djproj/djproj/celery.py中直接定义task
2 使用autodiscover 但是tasks必须定义在app目录下的名字为tasks.py的文件中,如:apps/app1/tasks.py 否则找不到 ,会报KeyError错误。
3 如果不使用autodiscover,可以在项目的celery中 import 相应的module,相当于在项目的celery中写了相应的task,如在celery.py中 import apps.app2.mytasks
4 在settings.py中设置CELERY_IMPORTS = ('apps.app2.mytasks',) 写到module级
第一,假设用户正发起一个request, 并等待request完成后返回.在这一request后面的view功能中,我们可能需要执行一段花费很长时间的程序任务,这一时间可能远远大于用户能忍受的范围.当这一任务并不需要立刻执行时,我们便可以使用Celery在后台执行,而不影响用户浏览网页.当有任务需要访问远程服务器完成时,我们往往都无法确定需要花费的时间.
第二则是定期执行某些任务.比如每小时需要检查一下天气预报,然后将数据储存到数据库中.我们可以编写这一任务,然后让Celery每小时执行一次.这样我们的web应用便能获取最新的天气预报信息.