Celery 初步使用心得

年底了,该给自己写个总结了,一个六年女Java程序员的心声 >>>  

一、 基本介绍

Celery是一个专注于实时处理和任务调度的分布式任务队列。所谓任务就是消息,消息中的有效载荷中包含要执行任务需要的全部数据。

使用Celery常见场景:

  1. Web应用。当用户触发的一个操作需要较长时间才能执行完成时,可以把它作为任务交给Celery去异步执行,执行完再返回给用户。这段时间用户不需要等待,提高了网站的整体吞吐量和响应时间。
  2. 定时任务。生产环境经常会跑一些定时任务。假如有上千台的服务器、上千种任务,定时任务的管理会很困难,Celery可以帮助我们快速在不同的机器设定不同种任务。
  3. 其他可以异步执行的任务。为了充分提高网站性能,对于请求和响应之外的那些不要求必须同步完成的附加工作都可以异步完成。比如发送邮件/短信、推送消息、清理/设置缓存等。

Celery特性:

  • 方便地查看定时任务的执行情况,比如执行是否成功、当前状态、执行任务花费的时间等。
  • 可以使用功能齐备的管理后台或者命令行添加、更新、删除任务。
  • 方便把任务和配置管理相关联。
  • 可选多进程、Evenlent和Gevent三种模式并发执行。
  • 提供多种错误处理机制。
  • 提供多种任务原语,方便实现任务分组、拆分和调用链。
  • 支持多种消息代理和存储后端。

Celery架构图:

产生任务的方式有两种:

  1. 发布者发布任务(Web应用)
  2. 任务调度按期发布任务(定时任务)

Celery组件介绍:

  • Celery Beat: 任务调度器,Beat进程会读取配置文件的内容,周期性地将配置中到期需要执行的任务发送给任务队列。
  • Celery Worker: 执行任务的消费者,通常会在多台服务器运行多个消费者来提高执行效率。
  • Broker: 消息代理,或者叫做消息中间件,接受任务生产者发送过来的任务消息,存进队列在按序分发给任务消费方。
  • Producer: 调用Celery提供的API、函数或者装饰器而产生任务并交给任务队列处理的都是任务生产者。
  • Result Backend: 任务处理完后保存状态信息和结果,以供查询。Celery默认支持Redis、RabbitMQ、MongoDB、Django ORM SQLAlchemy等方式。

Celery目前支持RabbitMQ、Redis、MongoDB、Beanstalk、Zookeeper、SQLAlchemy等作为消息代理,但用于生产环境只有RabbitMQ和Redis,官方推荐RabbitMQ来作为Celery的消息代理。

在客户端和消费者之间传输数据需要序列化和反序列化,Celery支持的序列化方案如下图

名称 介绍
pickle pickle是Python标准库中的一个模块,支持python内置的数据结构,但是它是Python的专有协议,从Celery 3.2开始,由于安全性等原因Celery拒绝支持pickle这个方案
json json支持多种语言,可用于跨语言方案
yaml yaml的表达能力更强,支持的数据类型比json多,但是python客户端的性能不如json
msgpack msgpack是一个二进制的类json的序列化方案,但是比json的数据结构更小、更快

二、安装配置Celery

为了提供更高的性能,采用如下方案:

  • 选择RabbitMQ作为消息代理。
  • RabbitMQ的Python客户端选择librabbitmq这个C库。
  • 选择Msgpack做序列化
  • 选择Redis做结果存储
sudo apt-get install rabbitmq-server
sudo apt-get install redis-server
sudo pip install "celery[librabbitmq,redis,msgpack]"

三、示例演示

项目目录结构

tree project
project
├── celeryconfig.py
├── celery.py
├── __init__.py
└── tasks.py

主程序celery.py:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 拒绝隐士引入,因为celery.py的名字和celery的包名冲突,需要使用这条语句让程序正确运行
from __future__ import absolute_import

from celery import Celery

# app是 Celery类的实例,创建的时候添加了project.tasks这个模块,也就是包含了project/tasks.py这个文件
app = Celery(‘project‘, include=[‘project.tasks‘])

# 把Celery配置存放进project/celeryconfig文件,使用app.config_from_object加载配置
app.config_from_object(‘project.celeryconfig‘)

if __name__ == ‘__main__‘:
    app.start()

任务函数文件tasks.py:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from __future__ import absolute_import

from project.celery import app

# 让任务函数生效的方法是添加app.task装饰器
@app.task
def add(x, y):
    return x + y

配置文件celeryconfig.py:

# -*- coding:utf-8 -*-
BROKER_URL = ‘amqp://guest:[email protected]:5672//‘  # 使用RabbitMQ作为消息代理
CELERY_TASK_PROTOCOL = 1  # 现在celery升级到了4.0,是老版本的librabbitmq与最新的celery4.0 Message Protocol协议不兼容,celery4.0默认使用Task messages Version 2 ,而librabbitmq使用Task messages Version 1
CELERY_RESULT_BACKEND = ‘redis://localhost:6379/0‘ # 把结果存在Redis
CELERY_TASK_SERIALIZER = ‘msgpack‘  # 任务序列化肯反序列化使用msgpack方案
CELERY_RESULT_SERIALIZER = ‘json‘   # 读取任务结果一般性能要求不高,所以使用可读性更好的json
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24  # 任务过期时间
CELERY_ACCEPT_CONTENT = [‘json‘, ‘msgpack‘] # 指定接收的内容类型

启动消费者:

[email protected]:~$ celery -A project.celery  worker -l info

-A 参数默认会寻找project.celery这个模块

看到如下信息说明worker服务运行起来了
 -------------- [email protected] v4.1.0 (latentcall)
---- **** -----
--- * ***  * -- Linux-4.4.0-92-generic-x86_64-with-Ubuntu-16.04-xenial 2017-11-21 09:35:15
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app:         project:0x7f9d656cd110
- ** ---------- .> transport:   amqp://guest:**@localhost:5672//
- ** ---------- .> results:     redis://localhost:6379/0
- *** --- * --- .> concurrency: 2 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery

[tasks]
  . project.tasks.add

[2017-11-21 09:35:19,030: INFO/MainProcess] Connected to amqp://guest:**@localhost:5672//
[2017-11-21 09:35:19,662: INFO/MainProcess] mingle: searching for neighbors
[2017-11-21 09:35:22,960: INFO/MainProcess] mingle: all alone
[2017-11-21 09:35:23,063: INFO/MainProcess] [email protected] ready.

上述信息提供了消息代理和存储结果的地址、并发数量、任务列表、交换类型等

开启另一个终端,用ipython调用add函数

In [1]: from project.tasks import add

In [2]: r = add.delay(1,3)

In [3]: r
Out[3]: <AsyncResult: a14d2045-ad40-4240-bbcf-1a8f07899485>

In [4]: r.result
Out[4]: 4

In [5]: r.status
Out[5]: u‘SUCCESS‘

In [6]: r.successful()
Out[6]: True

In [7]: r.backend
Out[7]: <celery.backends.redis.RedisBackend at 0x7faae433a450>  # 保存在redis中

worker终端上显示执行了任务:

[2017-11-21 09:37:45,681: INFO/MainProcess] Received task: project.tasks.add[a14d2045-ad40-4240-bbcf-1a8f07899485]
[2017-11-21 09:37:45,923: INFO/ForkPoolWorker-2] Task project.tasks.add[a14d2045-ad40-4240-bbcf-1a8f07899485] succeeded in 0.238272875s: 4

任务的task_id根据上面提到的task_id获得,可以用下面方法获得结果

方法一:

In [9]: task_id = ‘a14d2045-ad40-4240-bbcf-1a8f07899485‘

In [10]: add.AsyncResult(task_id).get()
Out[10]: 4

方法二:

In [12]: from celery.result import AsyncResult

In [13]: AsyncResult(task_id).get()
Out[13]: 4

另外redis库中存放了key为task_id 的值,如下所示

[email protected]:~$ redis-cli
127.0.0.1:6379> keys *
1) "celery-task-meta-a14d2045-ad40-4240-bbcf-1a8f07899485"
127.0.0.1:6379> get celery-task-meta-a14d2045-ad40-4240-bbcf-1a8f07899485
"{\"status\": \"SUCCESS\", \"traceback\": null, \"result\": 4, \"task_id\": \"a14d2045-ad40-4240-bbcf-1a8f07899485\", \"children\": []}"

原文地址:https://www.cnblogs.com/ziyide/p/10172387.html

时间: 2024-10-09 23:25:58

Celery 初步使用心得的相关文章

关于使用CELERY的一点心得

使用也有大半年了.稳定性没话说啊. 但有一个坑,是我以前没注意的,记录下来. 就是本来一个任务是可以异步并行执行的..但如何需要CELERY的执行结果来作判断的话,就会变得异步串行的. 这要值得注意. 比如以下这段代码的实现,开始,我用RESULT结果判断再来更新数据库,就变成串行的,一次只能启动一个worker, 于是,我将更新数据库放到同一个deplay函数之后,就可以并行执行啦. def rsync_dir(site_name, app_name, deploy_version): fil

web前端初步学习心得

  图像主要由文字.图像和超链接等元素构成.当然,除了这些元素,网页中还可以包含音频.视频以及flash等. 网页主要由三部分组成:结构哦.表现和行为.对应的标准也分三方面:结构化标准和语言主要包括XHTML和XML,表现标准语言主要包括CSS,行为标准主要包括对象模型(如DOM).ECMAScript等. @网页组成:结构,表现,行为.   @结构:网页的结构部分(骨架):   @表现:网页的样式(外衣):   @行为:网页主要实现的交互功能(使网站动起来)     web标准的好处1.让we

bootstrap使用心得及css模块化的初步尝试

第一次用bootstrap到实战项目,是一个企业门户站,可以说是强行拿bootstrap上来练手,感觉并不适合. 我是用的less编译bootstrap文件,直接改less变量.然后把不可重用的部分,比如页面头部,单独用一个app.css文件来覆盖. 发现bootstrap的字体实在是不行,本身就是给外国佬设计的,前几天看到一个neat.css据说是把normalize根据国情改进过的,拿来用了感觉还不错. 目前的想法是把网站会复用的部分调用bootstrap来实现,或者样式有差别的直接改les

初步接触html心得

接触HTML大概有七天,做一下小总结,过过记忆. html大致可分为三部分:Dtd头.Head.Body三大部分. Dtd头:是用于浏览器编辑的,也就是俗话说的给电脑看的的东西. Head:内细分下大概有title(标题).base(将相对url转换为绝对url).link(使用外部链接时使用).style(声明样式).meat(定义文件信息)等组成Html的头部部分. body:这是整个Html中最重要的部分,也就是说的给人看的部分.它由主体部分中各类标签组合而成,其中重要的部分有:样式标签.

学习前端第二天心得体会(初步了解HTML5的部分API以及画布Canvas)

一.HTML5部分API 1.选择器querySelector和querySelectorAll 1.1.querySelector:返回文档中匹配指定的CSS选择器的第一元素.  document.querySelector(CSS selectors),CSS selectors(指定一个或多个匹配元素的 CSS 选择器. 可以使用它们的 id, 类, 类型, 属性, 属性值等来选取元素. 对于多个选择器,使用逗号隔开,返回一个匹配的元素). 1.2.querySelectorAll : H

Linux系统理解以及Linux系统学习心得

原创作品转载请注明出处  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 作者:严哲璟 说一下我对Linux系统的理解 1.加载Linux内核准备:在加载基本输入输出模块(BIOS)之后,从磁盘的引导扇区读入操作系统的代码文件块到内存中,之后开始整个系统的初始化. 2.main.c的start_kernel函数是整个操作系统的入口,这也与Linux是基于C语言的特性相符,start_kernel具体做的动作很多

【管理心得之二十二】小人物 仰视 大授权

场景再现====================Boss:小王,来我办公室一下.小王: 嗯Boss:近期总公司有会,需要到外地出差几日.我不在的这段期间里,公司大小事务你帮忙处理一下.          如果有什么难决定的事,第一时间电话.邮件联系我商定即可.小王:  明白.放心吧领导,绝不会让你失望的Boss:嗯,那就好,没事了. {小王走出办公室} 心中暗喜,"难道这就是传说中的授权,Boss不在的时候,我岂不是最高权力的行使者." ==================== 从场景

第五周心得

本周学习的课程较难,主要接触了集合框架.反射以及部分Swing包含内容. 首先集合框架,主要要掌握的知识点如下: java集合框架的层次结构,使用Collection接口定义的公用方法对集合和线性表操作 使用Iterator接口遍历集合,使用JDK的增强for each循环替代迭代Iterator进行集合遍历 list接口的熟练应用,个人感觉应该是使用最广泛的了 熟练掌握Collection接口以及Arrays类中常用的静态方法. 熟悉set接口,知道set和list的区别.知道如何用hashs

【管理心得之二十四】成功乃失败之母

场景再现 ======================= Boss:侯さん,这次项目做得不错. 一,得到日本客户的高评, 二,争取到了新客户 三,新领域尝试是正确的 所谓是"一箭三雕",年底一定给你们团队一个嘉奖. 侯さん:哪里哪里,若不是您在背后的大力支持,"巧妇难为无米之炊"哪里有今天的成果. Boss:切忌"成功是失败之母",你去忙吧. 侯さん:嗯------? {侯さん走出办公室,心想---..} "这Boss有点意思,耳熟能详