RabbitMq +Celery(三)

一、Celery简介

Celery 本身不是任务队列, 是管理分布式任务队列的工具. 它封装了操作常见任务队列的各种操作, 我们使用它可以快速进行任务队列的使用与管理.Celery是一个专注于实时处理和任务调度的分布式任务队列。同时提供操作和维护分布式系统所需的工具,它的基本工作就是管理分配任务到不同的服务器,并且取得结果。至于说服务器之间是如何进行通信的?这个Celery本身不能解决。

Celery在执行任务时需要一个消息中间件来接收和发送任务消息,以及存储任务结果,一般使用RabbitMQ 或 Redis,我们这里只讨论Celery+RabbitMQ,其他的组合方式读者可以查阅更多资料。

所谓任务就是消息, 消息包含有效载荷(payload)和标签(label),有效载荷中包含要执行任务传输需要的全部数据,可以轻松实现任务的异步处理;标签描述了有效载荷,并决定谁获得消息。举个栗子:AMQP只会用标签表述一条消息(一个交换器的名称和可选的主题标记),然后把消息交由rabbit,rabbit会根标签把消息发送给感兴趣的接收方,但是接收方只根据规则接收消息(有效载荷),并不会接收标签,也就是接收方不会知道是谁发送了消息。

优点:

简单:一旦熟悉了Celery的工作流程后,配置和使用是比较简单的。

高可用:当任务执行失败或执行过程中发生连接中断,Celery 会自动尝试重新执行任务。

快速:一个单进程的Celery每分钟可处理上百万个任务。

灵活: Celery的大部分组件都可以被扩展及自定制。

二. celery 组件

1. Celery 扮演生产者和消费者的角色,

Celery Beat : 任务调度器. Beat 进程会读取配置文件的内容, 周期性的将配置中到期需要执行的任务发送给任务队列.

Celery Worker : 执行任务的消费者, 通常会在多台服务器运行多个消费者, 提高运行效率.

Broker : 消息代理, 队列本身. 也称为消息中间件. 接受任务生产者发送过来的任务消息, 存进队列再按序分发给任务消费方(通常是消息队列或者数据库).

Celery默认的Broker是RabbitMQ

Producer : 任务生产者. 调用 Celery API , 函数或者装饰器, 而产生任务并交给任务队列处理的都是任务生产者.

Result Backend : 任务处理完成之后保存状态信息和结果, 以供查询.

Celery架构图

2. 产生任务的方式 :

1.发布者发布任务(WEB 应用)

2.任务调度按期发布任务(定时任务)

3.依赖库

kombu : Celery 自带的用来收发消息的库, 提供了符合 Python 语言习惯的, 使用 AMQP 协议的高级接口.

4.序列化

在客户端和消费者之间传输数据需要 序列化和反序列化. Celery 支出的序列化方案如下所示:

三、Celery+RabbitMQ是如何工作的?

关于Celery和RabbitMQ的协作方式,可以通过工作上的一些案例来说明:

假设A公司最近在开下年度工作会议,会议上要确定下一年的工作内容和计划,参会人员有老板(下发任务者)、部门主管(Celery分配任务者)、部门员工(工作者)、老板秘书(沟通协调者RabbitMQ)。

那么这场会议首先需要确定的是下一年的具体工作内容,这里就称之为“任务内容”。比如老板说我们下一年要开发出一款社交类APP产品,部门主管表示赞同,于是便愉快地定下了具体的工作任务(task),当然开发一款社交类APP产品是这个项目的总任务,其中可以细分成很多小的任务,比如业务流程是怎么样的?界面怎么设计等。

在确定了具体工作任务后,老板便把这个项目交给了部门主管(Celery),部门主管确定部门员工中谁去完成这项任务,于是指定某个人(Worker),也可以多个人。

发布工作任务的人是老板(下发任务者),他指定了部门主管(Celery)什么时候去完成哪些任务,并要求获取反馈信息。但有一点需要注意,老板只管布置任务,不参与具体的任务分配,这个任务分配的工作是交给部门主管(Celery)去执行。

项目之初,老板(下发任务者)通过公司会议将任务传递给部门主管(Celery),部门主管通过部门会议将任务分配给员工(Worker),过段时间再将任务结果反馈给老板。然而随着任务越来越多,部门主管发现任务太多,每个任务都要反馈结果,记不住,也容易弄乱,导致效率下降。

在召开会议商量了一番后,老板秘书(沟通协调者RabbitMQ)站起来说:“我有个提议,老板每天将布置的任务写成一张纸条放到我这,然后部门主管每天早上来取并交给员工,至于纸条上的任务如何分配,部门主管决定就行,但是要将结果同样写一张纸条反馈给我,我再交给老板。这样老板只负责下发任务,我只负责保管任务纸条,部门主管只负责分配任务并获取反馈,员工只负责按任务工作。大家职责都很明确,效率肯定会更高。”至此,老板与员工的沟通问题也解决了。

四、使用Celery+RabbitMq

1.Celery安装使用

Celery是一个Python的应用,而且已经上传到了PyPi,所以可以使用pip或easy_install安装:

1
2
3
pip install celery

pip instal kombu

2.创建Application和Task

Celery的默认broker是RabbitMQ,仅需配置一行就可以:

1
broker_url = 'amqp://guest:guest@localhost:5672//'

创建一个Celery Application用来定义任务列表。

实例化一个Celery对象app,然后通过@app.task 装饰器注册一个 task。任务文件就叫tasks.py:

1
2
3
4
5
6
7
8
9
from celery import Celery

app = Celery(__name__, broker='amqp://guest:guest@localhost:5672//')

@app.task

def add(x, y):  

        return x + y

3.运行 worker,启动Celery Worker来开始监听并执行任务

在 tasks.py 文件所在目录运行

1
$ celery worker -A tasks.app -l INFO

这个命令会开启一个在前台运行的 worker,解释这个命令的意义:

worker: 运行 worker 模块。

-A: –app=APP, 指定使用的 Celery 实例。

-l: –loglevel=INFO, 指定日志级别,可选:DEBUG, INFO, WARNING, ERROR, CRITICAL, FATAL

其它常用的选项:

-P: –pool=prefork, 并发模型,可选:prefork (默认,multiprocessing), eventlet, gevent, threads.

-c: –concurrency=10, 并发级别,prefork 模型下就是子进程数量,默认等于 CPU 核心数

完整的命令行选项可以这样查看:

1
$ celery worker --help

4.调用Task

再打开一个终端, 进行命令行模式,调用任务。

1
2
3
4
5
from tasks import add

add.delay(1,2)

add.apply_async(args=(1,2))

上面两种调用方式等价,delay() 方法是 apply_async() 方法的简写。这个调用会把 add 操作放入到队列里,然后立即返回一个 AsyncResult 对象。如果关心处理结果,需要给 app 配置 CELERY_RESULT_BACKEND,指定一个存储后端保存任务的返回值。

七、在项目中的简单使用流程

1)RabbitMQ所在服务器,启动crontab设置 crontable -user user -e设置定时执行celery application应用。

1
python tasks.py day

2)在task.py文件里面启动一个叫做app的Celery Application,编写一个app.task函数来produce 任务到rabbitmq。

1
2
3
app = Celery()

app.config_from_object(celeryconfig)

3)在每个worker里面通过命令启动worker消费任务

1
$ celery worker -A tasks.app -l INFO