一、celery 架构
从图上我们可以看出celery包含几个模块
任务模块
主要包括异步任务和定时任务,异步任务通常在业务逻辑中被触发并发送到任务队列中,而定时任务是由Celery Beat进程周期性的将任务发往任务队列。
消息中间件 Broker
Broker就是任务调度队列,接收任务生产者发送过来的消息,将任务存入队列,之所以需要中间人的原因是Celery本身是不提供消息队列的服务,所以需要第三方组件实现,包括RabbitMQ,Redis,MongoDB等,我这里先了解下Redis
任务执行单元 Worker
Worker是执行任务的单元,它实时的监控消息队列,如果有任务就获取它并执行,它并发的运行分布在系统节点中。
任务结果存储
backend用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括Redis,MongoDB,Django ORM,AMQP等,这里我先不去看它是如何存储的,就先选用Redis来存储任务执行结果。
二、celery和Redis的安装
1、celery的安装
sudo pip install celery
2、redis的安装
sudo pip install redis
然后进行简单的配置
BROKER_URL = 'redis://localhost:6379/0'
URL的格式为:
redis://:password@hostname:port/db_number
URL Scheme 后的所有字段都是可选的,并且默认为 localhost 的 6379 端口,使用数据库 0。我的配置是:
BROKER_URL = 'redis://localhost:6379/15'
三、异步任务
使用celery实现异步任务主要包含三个步骤:
1、创建一个celery实例
2、启动CeleryWorker
3、应用程序调用异步任务
四、入门测试:
1、创建Celery实例
task1.py
-*- coding:utf-8 -*-
import time
from celery import Celery
from config import BROKER_URL,CELERY_RESULT_BACKEND
app=Celery('tasks1',
broker=BROKER_URL, #BROKER_URL = 'redis://localhost:6379/15'
backend=CELERY_RESULT_BACKEND) #CELERY_RESULT_BACKEND = 'redis://localhost:6379/15'
@app.task
def Sendmessage(message): #任务
print message
time.sleep(2)
return message
上边的代码创建了一个Celery实例,名称为tasks1
指定消息中间件为redis
指定存储用redis
创建了一个任务为Sendmessage,当函数被@app.task装饰后,就成为可被Celery调度的任务
2、启动worker
在当前目录下使用下边的方法来启动
celery worker -A task1 --loglevel=info
其中:
参数 A 指定了Celery实例的位置,本例是在task1.py中,Celery会自动在该文件中寻找Celery对象实例,当然我们也可以自己指定,在本例使用 -A task1.app;
参数 –loglevel指定了日志级别,默认为warning,也可以用 -l info来表示
启动成功后显示以下输出
-------------- celery@apple v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.2.0-27-generic-x86_64-with-Ubuntu-14.04-trusty 2017-11-28 16:17:35
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: tasks1:0x7fc4c34ebc10
- ** ---------- .> transport: redis://localhost:6379/15
- ** ---------- .> results: redis://localhost:6379/15
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. task1.Sendmessage
[2017-11-28 16:17:35,374: INFO/MainProcess] Connected to redis://localhost:6379/15
[2017-11-28 16:17:35,377: INFO/MainProcess] mingle: searching for neighbors
[2017-11-28 16:17:36,386: INFO/MainProcess] mingle: all alone
[2017-11-28 16:17:36,394: INFO/MainProcess] celery@apple ready.
3、调用任务
重新打开一个控制台,在当前目录打开python控制台,
>>> from task1 import Sendmessage
>>> Sendmessage.delay('Hello lijiajia')
<AsyncResult: 51dce370-076c-4222-a5d4-88722c8da630>
在上边我们从task1.py中导入了Sendmessage任务对象,然后使用delay()方法将任务发送到消息中间件Broker,Celery Worker进程监控到该任务后,就会进行执行,将窗口切换到worker 窗口,就会看到以下输出:
[2017-11-28 16:21:11,345: INFO/MainProcess] Received task: task1.Sendmessage[51dce370-076c-4222-a5d4-88722c8da630]
[2017-11-28 16:21:11,347: WARNING/ForkPoolWorker-4] Hello lijiajia
[2017-11-28 16:21:13,366: INFO/ForkPoolWorker-4] Task task1.Sendmessage[51dce370-076c-4222-a5d4-88722c8da630] succeeded in 2.01967258751s: 'Hello lijiajia'
说明任务已经被调度并执行成功。
我们如果想获取执行后的结果,可以这样:
>>> res=Sendmessage.delay('I am Studying Celery')
>>> res.ready() #使用ready()查看任务是否执行完毕
True
>>> res.get() #使用get()获取任务结果。
u'I am Studying Celery'
上边我们是在python 环境中调用任务,事实上我们通常在应用程序中调用任务
client.py
-*- coding:utf-8 -*-
from task1 import Sendmessage
#异步任务
Sendmessage.delay('i am lijiajia')
print 'hello ,i am lijiajia'
运行命令python client.py,虽然任务函数 Sendmessage需要两秒才返回结果,但他由于是异步任务,不会阻塞当前的任务环境,因此主程序会往下执行print语句,打印出结果
worker中输出:
[2017-11-28 16:31:57,444: INFO/MainProcess] Received task: task1.Sendmessage[70b97e6b-62ac-40bc-ad0a-1e0d67a8c706]
[2017-11-28 16:31:57,445: WARNING/ForkPoolWorker-4] i am lijiajia
[2017-11-28 16:31:59,448: INFO/ForkPoolWorker-4] Task task1.Sendmessage[70b97e6b-62ac-40bc-ad0a-1e0d67a8c706] succeeded in 2.00329515897s: 'i am lijiajia'
打印结果:
(.celenv) lijiajia@apple:~/Celerystudy/celery_app$ python client.py
hello ,i am lijiajia