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. SAP中常用SM系列事务代码总结

    SM01 锁定事物 SM02 系统信息 SM04 显示在线用户 SM12 删除,显示锁对象 SM13 看update  request SM21 看下系统日志 SM30|SM31 维护table|vi ...

  2. jquery-easyUI第二篇【综合案例】

    基于easyUI开发的一个综合案例模版 <%@ page language="java" pageEncoding="UTF-8"%> <!D ...

  3. 纳税服务系统【统计图Fusionchart】

    需求 我们在投诉模块中还有一个功能没有实现: 统计:根据年度将相应年度的每个月的投诉数进行统计,并以图表的形式展示在页面中:在页面中可以选择查看当前年度及其前4年的投诉数.在页面中可以选择不同的年度, ...

  4. 命令行的目录栈(pushd指令与popd指令)

    在命令行下经常需要切换目录,通常的做法是手打目录名,而如果有时候我们需要临时离开一个目录去操作什么,过会再回来,重新打一次目录想必是很麻烦的,这时候就可以用目录栈了,直接pushd 目录,然后就放心的 ...

  5. 反转字符串的几种实现(Java)

    反转字符串的几种实现(Java) 首先第一种是利用Java中的类库对象进行反转 //第一种 使用Java类库的diam实现反转 public String reverse(String str){ S ...

  6. MySQL线程池的引入可以提高我们的MySQL的性能

    支持线程池的版本:MySQL 企业版本,MySQL percona的分支 MariDB 的版本.我们知道我们的MySQL 语句是不支持硬解析的,没有无SQL 解析 cache.每个连接对应一个线程,我 ...

  7. 已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍

    前言 本节我们来介绍一款强大的库Polly,Polly是一种.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略. Polly针对对.NET 4. ...

  8. SSH端口转发详解及实例

    一.SSH端口转发简介 SSH会自动加密和解密所有SSH客户端与服务端之间的网络数据.但是,SSH还能够将其他TCP端口的网络数据通SSH链接来转发,并且自动提供了相应的加密及解密服务.这一过程也被叫 ...

  9. 第6章 Overlapped I/O, 在你身后变戏法 ---1

    这一章描述如何使用 overlapped I/O(也就是 asynchronous I/O).某些时候 overlapped I/O 可以取代多线程的功用.然而,overlapped I/O 加上co ...

  10. 每周分享一 之 webSocket

    一:什么是webSocket ? webSocket是HTML5出的新协议,WebSocket协议支持,在受控环境中运行不受信任代码的客户端与选择了该代码通信的远程主机之间进行双向通信. 简单翻译一下 ...