Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,它是一个专注于实时处理的任务队列, 同时也支持任务调度。Celery 中有两个比较关键的概念:
Worker: worker 是一个独立的进程,它持续监视队列中是否有需要处理的任务;
Broker: broker 也被称为中间人,broker 负责协调客户端和 worker 的沟通。客户端向队列添加消息,broker 负责把消息派发给 worker。
安装 Celery
$ pip install celery
安装 Broker
Celery 支持多种 broker, 但主要以 RabbitMQ 和 Redis 为主。在 RabbitMQ 和 Redis之间,该如何选择呢?
RabbitMQ is feature-complete, stable, durable and easy to install. It’s an excellent choice for a production environment.
Redis is also feature-complete, but is more susceptible to data loss in the event of abrupt termination or power failures.
Celery 官方明确表示推荐在生产环境下使用 RabbitMQ,Redis 存在丢数据的问题。所以如果你的业务可以容忍 worker crash 或者电源故障导致的任务丢失,采用 Redis 是个不错的选择,本篇就以 Redis 为例来介绍。
Celery 对于 Redis 的支持需要安装相关的依赖,以下命令可以同时安装 Celery 和 Redis 相关的依赖,但是 redis server 还是必须单独安装的。
$ pip install -U celery[redis] # -U 的意思是把所有指定的包都升级到最新的版本
Celery 的配置和使用
Celery 本身的配置项是很多的,但是如果要让它跑起来,只需要加一行配置:
BROKER_URL = 'redis://localhost:6379//'
这一行就是告诉 celery broker 的地址和选择的 redis db,默认是 0。接下来用个很简单的例子来介绍 celery 是如何使用的:
# tasks.py
from celery import Celery
app = Celery('tasks', broker='redis://localhost//')
@app.task
def add(x, y):
return x + y
以上创建了一个 celery 的实例 app,可以通过它来创建任务和管理 workers。
接下来运行 celery worker,通过它来监听是否有任务要处理:
$ celery -A tasks worker -l info
通过 celery worker –help 查看更多参数选项
接着再打开一个 shell 窗口,进入 python 控制台去调用 add 任务:
>>> from tasks import add
>>> add.delay(1, 2)
发现 add 任务并没有返回 3,而是一个对象 AsyncResult,它的作用是被用来检查任务状态,获取任务结果,如果任务失败,它会返回异常信息或者调用栈。
先尝试获取任务的执行结果:
>>> result = add.delay(1, 2)
>>> result.get()
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/celery/result.py", line 169, in get
no_ack=no_ack,
File "/usr/local/lib/python2.7/dist-packages/celery/backends/base.py", line 604, in _is_disabled
'No result backend configured. '
NotImplementedError: No result backend configured. Please see the documentation for more information.
报错了:No result backend configured. 错误信息告诉我们没有配置 result backend。因为 celery 会将任务的状态或结果保存在 result backend,result backend 的选择也有很多,本例中依然选用 redis 作为 result backend。
修改 tasks.py 的代码,添加上 result backend 的设置,保存后重启 celery worker。
app = Celery('tasks', backend='redis://localhost', broker='redis://localhost//')
然后重新调用 add task,看看是否获取到了执行结果?
>>> from tasks import add
>>> result = add.delay(1,2)
>>> result.get()
3
正确的获得到了结果!
Flower
flower 是一个 celery 的监控工具,它提供了一个图形用户界面,可以极大的方便我们监控任务的执行过程, 执行细节及历史记录,还提供了统计功能。
安装
$ pip install flower
使用简介
首先通过命令行启动 flower 进程:
$ flower -A tasks --port=5555
然后打开浏览器 http://localhost:5555/
Celery 任务类型
apply_async
调用一个异步任务,这也是最常用的任务类型之一,delay 与它的作用相同,只是 delay 不支持 apply_async 中额外的参数。该方法有几个比较重要的参数,在实际应用中会经常用到:
- countdown: 任务延迟执行的秒数,默认立即执行;
- eta:任务被执行的绝对时间
crontab schedules
from datetime import timedelta
from celery.schedules import crontab
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERYBEAT_SCHEDULE = {
# Executes every 30 seconds
'add-every-30-seconds': {
'task': 'tasks.add',
'schedule': timedelta(seconds=30),
'args': (16, 16)
},
# Executes every Monday morning at 7:30 A.M
'add-every-monday-morning': {
'task': 'tasks.add',
'schedule': crontab(hour=7, minute=30, day_of_week=1),
'args': (16, 16)
},
}
crontab-schedules
要启动定时任务,需要启动一个心跳进程:
$ celery -A tasks beat
或者加上 -B
参数
$ celery -A tasks worker -B -l info
使用 Celery 的常见场景:
Web 应用。当用户触发的一个操作需要较长时间才能执行完成时,可以把它作为任务交给Celery 去异步执行,执行完再返回给用户。这段时间用户不需要等待,提高了网站的整体吞吐量和响应时间。
定时任务。生产环境经常会跑一些定时任务。假如你有上千台的服务器、上千种任务,定时任务的管理很困难,Celery 可以帮助我们快速在不同的机器设定不同种任务。
其他可以异步执行的任务。为了充分提高网站性能,对于请求和响应之外的那些不要求必须同步完成的附加工作都可以异步完成。比如发送短信/邮件、推送消息等。
Celery 特性:
方便地查看定时任务的执行情况,比如执行是否成功、当前状态、执行任务花费的时间等。
可以使用功能齐备的管理后台或者命令行添加、更新、删除任务。
Celery 架构(包含如下组件):
Celery Beat:任务调度器,Beat 进程会读取配置文件的内容,周期性地将配置中到期需要执行的任务发送给任务队列。
Celery Worker:执行任务的消费者,通常会在多台服务器运行多个消费者来提高执行效率。
Broker:消息代理,或者叫作消息中间件,接受任务生产者发送过来的任务消息,存进队列再按序分发给任务消费者。由于 Celery 本身不含消息服务,所以需要使用第三方消息服务来传递任务。目前,Celery 支持的消息服务有RabbitMQ、Redis甚至是数据库。
Producer:调用了 Celery 提供的 API、函数或者装饰器而产生任务并交给任务队列处理的都是任务的生产者。
Result Backend:任务处理完成后保存状态信息和结果,以供查询。
任务产生的两种方式:①发布者发布任务(web应用)②任务调度按期发布任务(定时执行)
Celery 序列化
在客户端和消费者之间传输数据需要序列化和反序列化,Celery 支持如下序列化方案。