关闭

Celery消息队列----路由任务

标签: celery消息队列路由广播
418人阅读 评论(0) 收藏 举报
分类:

基础

自动路由

最简单的路由方式是使用 task_create_missing_queues 设置 (默认是开启的)。

这个设置开启后, 一个在task_queues中还未定义的命名队列会被自动创建。这让简单的路由任务变得很容易。
假如你有两台服务器x 和 y,来处理常规(regular)任务,一个服务器z只处理feed相关的任务。你可以使用这样的配置:

task_routes = {'feed.tasks.import_feed': {'queue': 'feeds'}}

这个路由启用( enabled)后import_feed任务会被路由给“feeds”队列, 并且所有其他任务会被路由到默认队列(由于历史原因这个队列叫“celery”)。

除此以外,你可以使用全局模式匹配,或者正则表达式,匹配所有在feed.tasks 命名空间中的任务:

app.conf.task_routes = {'feed.tasks.*': {'queue': 'feeds'}}

如果匹配模式的顺序很重要,你应该在条目列表中指定路由器:

task_routes = ([
(‘feed.tasks.*’, {‘queue’: ‘feeds’}),
(‘web.tasks.*’, {‘queue’: ‘web’}),
(re.compile(r’(video|image).tasks..*’), {‘queue’: ‘media’}),
],)

注意
task_routes设置既可以是一个字典,也可是路由器对象的列表,所以在这种情况下我们需要指定设置为一个包含列表的元组(tuple)。

配置好路由器后,你可以开启服务器z来只处理feeds队列:

user@z:/$ celery -A proj worker -Q feeds

你可以指定很多队列,所以你也可以让这个服务器处理默认队列:

user@z:/$ celery -A proj worker -Q feeds,celery

改变默认队列的名字

你可以通过下面的配置改变默认队列的名字:

app.conf.task_default_queue = 'default'

队列是怎么被定义的

这样处理是对用户隐藏了AMQP协议的复杂性,而只提供基本的需求。然而你可能仍然对于队列的声明感兴趣。
使用下面的设置,一个名为“video” 的队列会被创建:

{'exchange': 'video',
 'exchange_type': 'direct',
 'routing_key': 'video'}

像Redis 或 SQS这样的非AMQP的后端,不支持交易所(exchange),所以他们需要exchange同队列有相同的名字。使用这个设计可以确保对他们也有效。

手动路由

假如你有两台服务器x 和 y,来处理常规(regular)任务,一个服务器z只处理feed相关的任务,你可以使用这样的配置:

from kombu import Queue

app.conf.task_default_queue = 'default'
app.conf.task_queues = (
    Queue('default',    routing_key='task.#'),
    Queue('feed_tasks', routing_key='feed.#'),
)
task_default_exchange = 'tasks'
task_default_exchange_type = 'topic'
task_default_routing_key = 'task.default'

task_queues 是Queue 实例的列表.。如果你没有给一个键设置exchange或者exchange类型,这些会从task_default_exchange和task_default_exchange_type设置中取。
为了路由任务到feed_tasks 队列,你可以在task_routes 设置中添加一个容器:

task_routes = {
‘feeds.tasks.import_feed’: {
‘queue’: ‘feed_tasks’,
‘routing_key’: ‘feed.import’,
},
}
你也可以给Task.apply_async()或者send_task()使用routing_key参数覆盖这个配置:

>>> from feeds.tasks import import_feed
>>> import_feed.apply_async(args=['http://cnn.com/rss'],
...                         queue='feed_tasks',
...                         routing_key='feed.import')

为了让服务器z从feed队列消费,你可以使用celery worker -Q 选项启动它:

user@z:/$ celery -A proj worker -Q feed_tasks --hostname=z@%h

服务器 x 和 y 必须被配置成从默认队列消费:

user@x:/$ celery -A proj worker -Q default --hostname=x@%h
user@y:/$ celery -A proj worker -Q default --hostname=y@%h

如果你想,甚至可以让你的处理feed的工人(worker)也处理正规(regular)任务:

user@z:/$ celery -A proj worker -Q feed_tasks,default --hostname=z@%h

如果你有另一个队列但想要绑定在另一个交易所,你可以指定一个自定义交易所和交易类型:

from kombu import Exchange, Queue
app.conf.task_queues = (
    Queue('feed_tasks',    routing_key='feed.#'),
    Queue('regular_tasks', routing_key='task.#'),
    Queue('image_tasks',   exchange=Exchange('mediatasks', type='direct'),
                           routing_key='image.compress'),
)

如果你对这些名词感到一头雾水,可以去参考AMQP。

。。。。。。。。。。。。。。。。

路由任务

定义队列

在Celery中可用的队列通过task_queues设置被定义。
这有一个队列配置的例子,它配置了三个队列;一个给video,一个给images还有一个给别的东西的默认队列:

default_exchange = Exchange('default', type='direct')
media_exchange = Exchange('media', type='direct')

app.conf.task_queues = (
    Queue('default', default_exchange, routing_key='default'),
    Queue('videos', media_exchange, routing_key='media.video'),
    Queue('images', media_exchange, routing_key='media.image')
)
app.conf.task_default_queue = 'default'
app.conf.task_default_exchange = 'default'
app.conf.task_default_routing_key = 'default'

这里面, task_default_queue 会被用来路由那些没有明确路由的任务。
默认的交易所,交易类型和路由键会作为任务的默认路由值,并且作为task_queues中登记注册(entries)的默认值。

也支持多重绑定到单一队列。下面是两个路由键都绑定到相同队列的例子:

from kombu import Exchange, Queue, binding

media_exchange = Exchange('media', type='direct')

CELERY_QUEUES = (
    Queue('media', [
        binding(media_exchange, routing_key='media.video'),
        binding(media_exchange, routing_key='media.image'),
    ]),
)

指定任务终点Specifying task destination

一个任务的终点由下面来决定(按次序):
在task_routes中定义的Routers。
The Routers defined in task_routes.
给Task.apply_async()的路由参数。
The routing arguments to Task.apply_async().
定义在Task自身中的路由相关的属性。
Routing related attributes defined on the Task itself.
一般最好不要硬编码这些设置,而是通过使用Routers把那个作为配置选项。这是最灵活的途径,但明确合理的默认值仍然可以被设置为任务属性。

路由器Routers

路由器是一个为任务决定路由选项的的函数。A router is a function that decides the routing options for a task.

定义一个新路由器时,你所要做的就是定义一个函数,带有签名 (name, args, kwargs, options, task=None, **kw):

def route_task(name, args, kwargs, options, task=None, **kw):
        if name == 'myapp.tasks.compress_video':
            return {'exchange': 'video',
                    'exchange_type': 'topic',
                    'routing_key': 'video.compress'}

如果你返回了队列的键,它会用task_queues中的那个队列已定义的设置进行扩展:

{'queue': 'video', 'routing_key': 'video.compress'}

变成 –>

{'queue': 'video',
 'exchange': 'video',
 'exchange_type': 'topic',
 'routing_key': 'video.compress'}

通过把他们添加到task_routes设置中来配置路由器类:

task_routes = (route_task,)

Router 函数也可以通过名字添加:

task_routes = ('myapp.routers.route_task',)

对于简单的任务名For simple task name -> 路由映射就像上面的路由器例子,你可以简单的把一个字典放到task_routes中,获取同样的表现:

task_routes = {
    'myapp.tasks.compress_video': {
        'queue': 'video',
        'routing_key': 'video.compress',
    },
}

路由器们(routers)会被按次序探查,在第一个返回真值的路由器处停止,选择它作为任务的最终路由。

你也可以在一个序列中定义多个路由器:
task_routes = [
route_task,
{
‘myapp.tasks.compress_video’: {
‘queue’: ‘video’,
‘routing_key’: ‘video.compress’,
},
]
路由器会被按次序访问,第一个返回值的会被选中。

广播Broadcast

Celery 也支持广播路由。这有一个 broadcast_tasks交易所的例子,它会传递任务的拷贝给所有连接到它的工人(workers)。:

from kombu.common import Broadcast

app.conf.task_queues = (Broadcast('broadcast_tasks'),)
app.conf.task_routes = {
    'tasks.reload_cache': {
        'queue': 'broadcast_tasks',
        'exchange': 'broadcast_tasks'
    }
}

现在tasks.reload_cache任务会被发送给从这个队列中消费的每一个工人。
这个广播路由的另一个例子,这次有一个celery定时器:

from kombu.common import Broadcast
from celery.schedules import crontab

app.conf.task_queues = (Broadcast('broadcast_tasks'),)

app.conf.beat_schedule = {
    'test-task': {
        'task': 'tasks.reload_cache',
        'schedule': crontab(minute=0, hour='*/3'),
        'options': {'exchange': 'broadcast_tasks'}
    },
}
0
0
查看评论

celery实现任务统一收集、分发执行

首先解释下目标的概念:celery任务消息会由各种途径(比如手动通过python shell触发、通过tornado触发等)发往统一的一个celery broker,然后任务消息会由不同server上的worker去获取并执行。具体点说就是,借助celery消息路由机制,celery broker中...
  • Vintage_1
  • Vintage_1
  • 2015-08-14 16:46
  • 8084

celery 消息队列与定时任务

在进行定时获取代理ip, 黑名单ip,以及进行ip校验,相关信息及特征获取时,需要用到定时任务,常见的使用 linux 的crontab 来实现定时任务。但是为了在使用django,保持设计的一致性,就采用 celery 消息队列的定时任务来做。开发环境: centos 7 python3.5 ...
  • a1368783069
  • a1368783069
  • 2017-01-18 12:23
  • 1220

【转】分布式异步任务队列 Celery + rabbitmq (or redis )

最近的项目要使用异步的任务队列,初步选用了Celery,比较轻量级,但是对Task,Broker,Worker等概念有些理解的不透彻,找到以下文章,甚是透彻。 当我们需要处理一些比较耗时的任务时,我们就需要考虑启用“异步”这个概念。 比如以下两种情况:一,频繁读写 比如说,现在你一条“微博”,...
  • u011897301
  • u011897301
  • 2016-03-29 10:53
  • 1888

Celery 分发任务

一、简介 Celery是基于分布式消息传递的开源异步任务队列。它侧重实时操作,也可用于计划任务。它的执行组件叫tasks,可在一个或多个worker节点上进行并行运算,支持的方式有multiprocessing,eventlet以及gevent。tasks可异步运行也可通过wait(),ready...
  • jazywoo123
  • jazywoo123
  • 2013-12-28 23:44
  • 4635

Celery 消息队列

简介在不同系统(或物理设备)之间,应用软件之间,程序进程之间,常常会有各种互相的信息传递;为保证消息传递的可靠性,对所传消息引入一个保存的容器:一方面用来接收发送者产生的信息,一方面在接收者正常的情况下完成消息的派送,并在无法接收消息时对信息进行存储,然后在适当的时机完成信息的派送。一般称该容器为消...
  • xsj_blog
  • xsj_blog
  • 2017-04-15 03:25
  • 1139

Celery 学习笔记(3)- 任务和任务执行

任务任务是 Celery 里不可缺少的一部分,它可以是任何可调用对象。每一个任务通过一个唯一的名称进行标识, worker 通过这个名称对任务进行检索。任务可以通过 app.task 装饰器进行注册,需要注意的一点是,当函数有多个装饰器时,为了保证 Celery 的正常运行,app.task 装饰器...
  • preyta
  • preyta
  • 2017-01-09 14:45
  • 2588

Celery用户指引------监控与管理

介绍 有一些监控和查看celery集群的工具。 这篇文章会介绍其中的一些,另外还有一些关于监控的特性,如果事件和广播命令。 Workers 命令行管理工具 celery也可以用来检查和管理worker节点(和对tasks在一定程度上的管理)。 列出所有可用的命令: $ celery help ...
  • happyAnger6
  • happyAnger6
  • 2016-06-06 23:01
  • 5347

celery 任务队列预取机制

我们启动celery基本命令为: celery -A mytask worker --loglevel=info 当以此命令启动celery后,celery默认情况下执行任务会有个预取机制(prefetching),预取是什么呢,如下一张图: 我们假设有两个worker,但当任务量...
  • zhubaoJay
  • zhubaoJay
  • 2017-04-07 17:00
  • 1196

celery expires 让celery任务具有时效性

起因:有的时候,我们希望任务具有时效性,比如定时每5分钟去抓取某个状态,由于celery队列中的任务可能很多,等到这个任务被执行时,已经超过了5分钟,那么这个任务的执行已经没有意义,因为下一次抓取已经执行了。
  • woshiaotian
  • woshiaotian
  • 2014-10-22 15:15
  • 1166

Celery(二)-----------------使用Celery的第二步

使用Celery的第一步是有意最小化的介绍Celery。本节教程将为你展示Celery提供的更多细节,包括怎样为你的程序和库添加Celery支持。 本节教程不会介绍Celery的所有特性和最佳实践,所以建议你也阅读一下用户指引 User Guide。 在你的程序中使用Celery 我们工程的结...
  • happyAnger6
  • happyAnger6
  • 2016-05-15 19:52
  • 7806
    个人资料
    • 访问:9558次
    • 积分:359
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:5篇
    • 译文:14篇
    • 评论:3条