Celery介绍和基本使用

Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, 举几个实例场景中可用的例子:

1)你想对100台机器执行一条批量命令,可能会花很长时间 ,但你不想让你的程序等着结果返回,而是给你返回 一个任务ID,你过一段时间只需要拿着这个任务id就可以拿到任务执行结果, 在任务执行ing进行时,你可以继续做其它的事情。
2)你想做一个定时任务,比如每天检测一下你们所有客户的资料,如果发现今天 是客户的生日,就给他发个短信祝福

Celery 在执行任务时需要通过一个消息中间件来接收和发送任务消息,以及存储任务结果, 一般使用rabbitMQ or Redis,后面会讲

1.1 Celery有以下优点:

    • 简单:一单熟悉了celery的工作流程后,配置和使用还是比较简单的
    • 高可用:当任务执行失败或执行过程中发生连接中断,celery 会自动尝试重新执行任务
    • 快速:一个单进程的celery每分钟可处理上百万个任务
    • 灵活: 几乎celery的各个组件都可以被扩展及自定制

  • Celery包含如下组件:

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

执行依靠

celery call 发送任务给这个 -->celery组件--->发送给rabbitmq,交给---->worker1|worker2

  • 环境的部署

    安装celery模块:pip install celery

基础代码worker端

from celery import Celery
app = Celery('tasks',broker='redis://:alex3714@192.168.14.52') #‘tasks’给app起的名字
backend='redis://alex3714@localhost')#将结果写入到哪 @app.task
def add(x,y):
print("running...",x,y)
return x+y @app.task
def cmd(cmd_str):
print('running cmd',cmd_str)

执行这个脚本: celery -A celery_test -l debug #当执行完这条命令后就会进入监听状态

#celery_test不用写后缀名, 指定模式。

调度端执行,会形成异步执行

from celery_test import add,cmd
add(4,5) #这么执行的话只是本地显示结果。
add.delay(45,2) #让worker端执行
t1 = add.delay(45,2)当你赋值的时候worker端还会在执行一次
t1.get() #获取执行的结果

celery -A celery_test worker -l info #在开一个客户端。

#这次我们测试这个任务是怎么分发的。
t2 = add.delay(22,44)
t2 = add.delay(22,44)
t2 = add.delay(22,44)
t2 = add.delay(22,44)
#当你执行的很快的时候你会发现这个任务和rabbit MQ一样是抢任务的。 from celery import Celery
app = Celery('tasks',broker='redis://:alex3714@192.168.14.52') #‘tasks’给app起的名字
backend='redis://alex3714@localhost')#将结果写入到哪 @app.task
def add(x,y):
print("running...",x,y)
return x+y @app.task
def cmd(cmd_str):
print('running cmd',cmd_str)
time.sleep(10)
return time.time()

调度端

from celery_test import add,cmd
t1 = cmd.delay('dsfsdf')
t1.get() #这时你会发现程序是阻塞的,并没有实现异步的效果
#当然这个解决也是非常简单的
t1.get(timeout=1,propa) #这时你会发现提示你任务没有完成
t1.ready() #可以查看任务没有没有完成,返回布尔值的状态

基础测试代码celery_test.py测试端:

from celery import Celery
app = Celery('proj',include=['proj.tasks']) #app是Celery类的实例,创建的时候添加了proj.tasks这个模块,也就是包含了proj/tasks.py这个文件。
app.config_from_object('proj.celeryconfig')把Celery配置存放进proj/celeryconfig.py文件,使用app.config_from_object加载配置。
if __name__ == '__main__'
app.start()

存放任务函数的文件tasks.py

from __future__ import absolute_import
from proj.celery import app @app.task #让这个任务生效的装饰器
def add(x, y):
return x + y

配置文件celeryconfig.py

BROKER_URL = 'amqp://dongwm:123456@localhost:5672/web_develop' # 使用RabbitMQ作为消息代理

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 # 任务过期时间,不建议直接写86400,应该让这样的magic数字表述更明显

CELERY_ACCEPT_CONTENT = ['json', 'msgpack'] # 指定接受的内容类型

启动上面的代码 celery -A celery_test -l info #-A指定人物名,不需要后缀,-l指定模式

开启另外一个终端,用IPython调用add函数:

from celery_test import add
r = add.delay(1,3) #在任务端执行一次
r #执行第二次
r.result #返回结果
r.status #返回状态
r.successful() #去执行结果
r.backend #保存到redis中 通过IPython触发的任务就完成了。任务的结果都需要根据上面提到的task_id获得,我们还可以用如下两种方式随时找到这个结果: task_id = '93288a00-94ee-4727-b815-53dc3474cf3f' In : add.AsyncResult(task_id).get() Out: 4 或者: In : from celery.result import AsyncResult In : AsyncResult(task_id).get() Out: 4

指定队列

Celery非常容易设置和运行,通常它会使用默认的名为celery的队列(可以通过CELERY_DEFAULT_QUEUE修改)用来存放任务。我们可以使用优先级不同的队列来确保高优先级的任务不需要等待就得到响应。

基于proj目录下的源码,我们创建一个projq目录,并对projq/celeryconfig.py添加如下配置:

指定队列

from kombu import Queue

CELERY_QUEUES = ( # 定义任务队列

Queue('default', routing_key='task.#'), # 路由键以“task.”开头的消息都进default队列

Queue('web_tasks', routing_key='web.#'), # 路由键以“web.”开头的消息都进web_tasks队列

)

CELERY_DEFAULT_EXCHANGE = 'tasks' # 默认的交换机名字为tasks

CELERY_DEFAULT_EXCHANGE_TYPE = 'topic' # 默认的交换类型是topic
CELERY_DEFAULT_ROUTING_KEY = 'task.default' # 默认的路由键是task.default,这个路由键符合上面的default队列
CELERY_ROUTES = {
'projq.test.add': { # tasks.add的消息会进入web_tasks队列
'queue': 'web_tasks',
'routing_key': 'web.add',
}
}

现在用指定队列的方式启动消费者进程:

celery -A projq worker -Q web_tasks -l info

上述worker只会执行web_tasks中的任务,我们可以合理安排消费者数量,让web_tasks中任务的优先级更高。

使用任务调度

之前的例子都是由发布者触发的,本节展示一下使用Celery的Beat进程自动生成任务。基于proj目录下的源码,创建一个projb目录,对projb/celeryconfig.py添加如下配置:

CELERYBEAT_SCHEDULE = {
'add': {
'task': 'celery_test.add',
'schedule': timedelta(seconds=10), #每10秒执行一次
'args': (16, 16) #执行的参数是
}
}

启动Beat程序:

celery beat -A projb

然后启动Worker进程:

celery -A projb worker -l info

之后可以看到每10秒都会自动执行一次tasks.add。

注:Beat和Worker进程可以一并启动:

celery -B -A projb worker -l info

使用Django可以通过django-celery实现在管理后台创建、删除、更新任务,是因为它使用了自定义的调度类djcelery.schedulers.DatabaseScheduler,我们可以参考它实现Flask或者其他Web框架的管理后台来完成同样的功能。使用自定义调度类还可以实现动态添加任务。

任务绑定、记录日志和重试

任务绑定、记录日志和重试是Celery常用的3个高级属性。现在修改proj/tasks.py文件,添加div函数用于演示:

from celery.utils.log import get_task_logger
logger = get_task_logger(__name__)
@app.task(bind=True)
def div(self, x, y):
logger.info(('Executing task id {0.id}, args: {0.args!r} '
'kwargs: {0.kwargs!r}').format(self.request))
try:
result = x / y
except ZeroDivisionError as e:
raise self.retry(exc=e, countdown=5, max_retries=3)
return result

当使用bind = True后,函数的参数发生变化,多出了参数self(第一个参数),相当于把div变成了一个已绑定的方法,通过self可以获得任务的上下文。

在IPython中调用div:

from proj.tasks import div
r = div.delay(2, 1)
[2017-09-20 15:50:31,853: INFO/Worker-1] proj.tasks.div[1da82fb8-20de-4d5a-9b48-045da6db0cda]: Executing task id 1da82fb8-20de-4d5a-9b48-045da6db0cda, args: [2, 1] kwargs: {}

换成能造成异常的参数:

In : r = div.delay(2, 0)

可以发现每5秒就会重试一次,一共重试3次(默认重复3次),然后抛出异常。

再来一张很给力的图 

celery rabbit mq 详解的更多相关文章

  1. celery+Rabbit MQ实战记录

    基于以前的一篇文章,celery+Rabbit MQ的安装和使用, 本文更加详细的介绍如何安装和使用celey, Rabbit MQ. 并记录在使用celery时遇到的一些问题. 1.安装 Rabbi ...

  2. JMS与MQ详解(有项目)

    <一>m2mGW项目 1.ActiveMQ概述     企业消息软件从80年代起就存在,它不只是一种应用间消息传递风格,也是一种集成风格.因此,消息传递可以满足应用间的通知和互相操作.但是 ...

  3. 消息中间件MQ详解及四大MQ比较

    一.消息中间件相关知识 1.概述 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流 ...

  4. 消息中间件(一)MQ详解及四大MQ比较

    一.消息中间件相关知识 1.概述 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流 ...

  5. 消息中间件之MQ详解及四大MQ比较

    一.消息中间件相关知识 1.概述 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流 ...

  6. 四大MQ比较及MQ详解

    消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之 一.当今市面上有很多主流的消息中间件,如老牌的Activ ...

  7. 详解RPC远程调用和消息队列MQ的区别

    PC(Remote Procedure Call)远程过程调用,主要解决远程通信间的问题,不需要了解底层网络的通信机制. RPC框架 知名度较高的有Thrift(FB的).dubbo(阿里的). RP ...

  8. celery详解

    目录 Celery详解 1.背景 2.形象比喻 3.celery具体介绍 3.1 Broker 3.2 Backend 4.使用 4.1 celery架构 4.2 安装redis+celery 4.3 ...

  9. RabbitMQ安装使用详解

    1.下载相应的版本安装:http://www.rabbitmq.com/download.htmleg:http://www.rabbitmq.com/releases/rabbitmq-server ...

随机推荐

  1. Oracle--新建用户以及赋予的权限

    1, 以dba方式登录Oracle 2, 创建用户,Users-->New ... 输入用户名和密码 3, 赋予connect/resource角色 4, 赋予该用户 对视图操作的相关权限 以下 ...

  2. String,StringBuffer,StringBuilder的区别及其源码分析

    String,StringBuffer,StringBuilder的区别这个问题几乎是面试必问的题,这里做了一些总结: 1.先来分析一下这三个类之间的关系 乍一看它们都是用于处理字符串的java类,而 ...

  3. 中国移动飞信WAP登陆分析及脚本

    中国移动飞信WAP网页版 http://f.10086.cn/im5/ 用WAP飞信登录并向好友发送信息,同时用wireshark抓包. 1.过滤POST表单提交数据包(wireshark规则: ht ...

  4. Glide 这样用,更省内存!!!

    一.前言 Glide 是 Google 官方推荐的一款图片加载库,使用起来也非常的简单便利,Glide 它帮我们完成了很多很重要,但是却通用的功能,例如:图片的加载压缩.展示.加载图片的内存管理等等. ...

  5. Kafka快速上手(2017.9官方翻译)

    为了帮助国人更好了解.上手kafka,特意翻译.修改了个文档.官方Wiki : http://kafka.apache.org/quickstart 快速开始 本教程假定您正在开始新鲜,并且没有现有的 ...

  6. hdu 5937 -- Equation(搜索)

    题目链接 problem description Little Ruins is a studious boy, recently he learned addition operation! He ...

  7. PHP常用字符串处理函数

    (1)strlen(string) 返回字符串长度 (2)strpos(string,find,begin) 返回find字符串第一次出现的位置(从0开始) string:处理的字符串 find:想找 ...

  8. 57、Bootstrap中文文档

    给大家介绍一个前端框架让你从此写起前端代码与之先前相比如有神助般的效果拉就是Bootstrap. 一.Bootstrap的下载 Bootstrap,由Twitter的设计师Mark Otto和Jaco ...

  9. MongoDB数据库的安装、配置和使用

    1.下载安装包   wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.7.tgz 2.解压安装包   tar -zxf mo ...

  10. webpack2使用ch4-向根目录index.html文件传参并使用参数 使用线上资源 压缩html

    1 webpack.config.js const webpack = require('webpack'), htmlWebpackPlugin = require('html-webpack-pl ...