简单的例子
在使用 Celery 的过程中主要的步骤如下:
- 定义一个应用,并在应用上注册任务;
- 启动 worker,通过消息队列等待任务;
- 通过在程序里调用预先注册的任务给 Celery 提交一个任务。
tasks.py 包含了一个简单的示例,来自于Celery的官方文档,主要进行了任务的注册,首先创建了一个 Celery 实例 app,这是 Celery 里的一个应用(Application),第一个参数是应用 名,Celery 的 worker 通过这个名字寻找应用;第二个参数是 broker 这里设置为本机的Redis Server。然后通过 app.task 装饰器为 app 这个应用注册一个任务。
#tasks.py
from celery import Celery
app = Celery('tasks',broker="redis://127.0.0.1:6379/0")
@app.task
def add(x,y):
return x + y
然后可以通过如下命令启动 worker, 其中 -A 参数用于指定在 tasks.py 里定义的应用的名字,–loglevel (等同于-l)用于指定日志的记录等级
celery -A tasks worker -l info
应该会看到一个大致这样的启动界面,下面解释下 [config] 的大致含义,其中 app 是 worker 对应的应用名,transport 是指在前面制定的消息队列地址,results 是指 任务执行结果存储的地方,但是这里没有指定,所以默认就是关闭的。concurrency 是 worker 的数量,默认和处理器的核心数相同。
然后启动另外一个终端,进入python工作环境,执行任务,如下图所示:
调用delay函数即可启动add这个任务,add函数的参数为4,4,这个函数的效果是发送一条消息到broker中去,这个消息包括要执行的函数已经执行函数的参数,还有一些其他信息,具体的可以看Celery的文档。
因为之前已经启动了一个worker,这个worker会等待broker中的消息,一旦收到消息就会立刻执行消息。
启动了一个任务之后,可以看到之前启动的worker已经开始执行任务了。效果如下图所示:
从上图中可以看到,任务已经被执行成功。
添加backend
Celery5.0起就不在支持amqp作为backend了,所以选择用RabbitMQ 作为broker,用redis作为backend。
安装RabbitMQ :参考Celery学习笔记(一)
安装redis服务器
linux安装
1.Download, extract and compile Redis with:
$ wget http://download.redis.io/releases/redis-3.2.8.tar.gz
$ tar xzf redis-3.2.8.tar.gz
$ cd redis-3.2.8
$ make
2.The binaries that are now compiled are available in the src directory. Run Redis with:
$ src/redis-server --protected-mode no
注意:开启服务器的时候指定 –protected-mode no,否则运行时会出错。
3.You can interact with Redis using the built-in client:
$ src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"
运行broker的机器上安装redis支持
对 Redis 的支持需要额外的依赖。你可以用 celery[redis] 捆绑 同时安装 Celery 和这些依赖:
pip install -U celery[redis]
或者 pip install "celery[librabbitmq,redis,msgpack]"
配置
#!/usr/bin/env python
# encoding: utf-8
from __future__ import absolute_import
from celery import Celery
app=Celery('myapp',broker='amqp://danny:123456789@192.168.1.128:5672/myvhost',backend='redis://192.168.1.128:6379/0',
include=['myapp.agent'])
app.config_from_object('myapp.config')
if __name__ == '__main__':
app.start()
获得任务的返回值
>>> res=add.delay(1,2)
>>> res.status
u'SUCCESS'
>>> res.get()
{u'value': u'3', u'node_name': u'docker1'}
Celery的一些配置
Celery的分布式实际包含两个层次:
- Distribute work on a given machine across all CPUs
- Distribute work to many machines
先说第一点,默认情况下,Celery在一台机器上启动worker,worker的进程数量和机器的CPU个数一致。但也可以通过concurrency参数控制启动worker的进程数量:
同时启动5个worker进程
celery -A tasks worker --loglevel=INFO --concurrency=5
比如你的机器只有一个CPU,但仍然可以通过上述方法启动5个worker进程,在某些IO密集型的任务中,可以考虑启动worker的数量多于CPU数量,在CPU密集型的任务中,这样的操作可能没有什么好处。
再说第二点,因为Celery只指定了worker的broker,所以只需要在不同机器上启动worker,它们都会从相同的broker中获取任务并处理。
在考虑不同机器上的操作时,涉及远程控制的概念。
celery inspect
观察所有运行worker的信息,例如观察当前处于活跃状态的worker和task:
celery -A tasks inspect active
celery control
控制worker的行为,例如向worker中增加对某队列的消费:
celery control -d w1.e.com add_consumer queue_name
celery status
观察当前worker状态
celery -A tasks status
# celery@iZ25d0yvrwwZ: OK
#
# 1 node online.
可见性超时
可见性超时时间定义了等待职程在消息分派到其他职程之前确认收到任务的秒数
这个选项通过 BROKER_TRANSPORT_OPTIONS 设置:
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600} # 1 hour.
Redis 的默认可见性超时时间是 1 小时
如果任务没有在 可见性超时 内确认接收,任务会被重新委派给另一个职程并执行。所以你需要增大可见性超时时间,以符合你计划使用的最长预计到达时间。
注意 Celery 会在职程关闭的时候重新分派消息,所以较长的可见性超时时间只会造成在断电或强制终止职程之后“丢失”任务重新委派的延迟。
你可以配置同名的传输选项来增大这个时间:
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 43200}
这个值必须是整数,单位是秒。