Celery 分发任务

来源:互联网 发布:网络带来的弊端 编辑:程序博客网 时间:2024/05/29 09:05
一、简介
Celery是基于分布式消息传递的开源异步任务队列。它侧重实时操作,也可用于计划任务。它的执行组件叫tasks,可在一个或多个worker节点上进行并行运算,支持的方式有multiprocessing,eventlet以及gevent。tasks可异步运行也可通过wait(),ready()同步运行。

消息broker推荐RabbitMQ,也可以是Redis,Beanstalk,MongoDB,CouchDB,关系型数据库(通过SQLAlchemy或Django ORM)。

二、总体架构
Celery - 一木头名誉坏 - 考研去
 Broker(RabbitMQ)将tasks发送到各个worker节点。worker节点是一组联网的电脑运行着一个或多个Celeryd实例。woker节点可根据负载情况部署。

三、特性

消息机制支持 RabbitMQ, Redis, Beanstalk, MongoDB, CouchDB, 以及 SQL 数据库.容错与 RabbitMQ配合可完美实现错误恢复分布式 运行于一台或多台服务器。支持Broker群集和HA,可任意添加worker而无需在服务器中心节点配置。并发通过Python的multiprocessing, Eventlet, gevent 或者他们的混合实现并发执行.Scheduling支持cron类的递归式任务,或者指定时间、倒数等任务执行方式.延迟极低延迟.返回值任务运行结果可储存在指定的结果存储后台,你可以等待结果或忽略运算结果返回值存储支持SQL数据库, MongoDB, Redis, Tokyo TyrantCassandra, 或 AMQP (消息通知).Webhooks用户跨语言/平台任务分配。Rate limitingSupports rate limiting by using the token bucket algorithm, which accounts for bursts of traffic. Rate limits can be set for each task type, or globally for all.  消息路由 通过AMQP灵活的路由模型你可以将任务路由到任意worker服务器,可配置或运行时指定。远程控制 可通过广播消息远程控制worker节点。Celery内置了大量的相关命令,也可以轻松实现自定义命令(只适用AMQP和Redis)监控可实时获得workers的一切信息对象序列化支持 Pickle, JSON, YAML,或自定义序列化程序. 错误追踪 UUID每个任务都有一个UUID用于查询该任务的运行状态以及返回值。出错重试当任务执行失败时可根据配置重试。配置内容包括最大重试次数,重试时间间隔。任务集任务集由多个子任务构成,可以获得子任务的数量,执行情况,以及各个子任务的运算结果。Made for Web可通过Ajax查询任务运行状态和运行结果。出错通知当任务出错是可通过邮件通知管理员
四、实战(演示级代码)
1、安装celery
   $ pip install celery      
   或者
   $ easy_install celery   

2、安装RabbitMQ
    go to here

3、安装mongodb,配置
    go to here

4、服务器设置
      服务器A:192.168.1.102, consumer,(worker server),安装mongodb,pymongo,RabbitMQ,Celery
      服务器B:192.168.1.104, producer,安装pymongo,Celery
      我们要做的是在服务器A上编写具体的任务,服务器B调用服务器A的任务

5、服务器A代码
celeryconfig.py:
CELERY_IMPORTS = ("Tasks.user","tasks.test",)

BROKER_HOST = "192.168.1.102"
BROKER_PORT = 5672 #默认的端口
BROKER_USER = 'sns'  #rabbitmq的配置参考相关文章
BROKER_PASSWORD = "sns"
BROKER_VHOST = "sns_host"
CELERY_RESULT_BACKEND = "mongodb"
CELERY_MONGODB_BACKEND_SETTINGS = {
    'host':'192.168.1.102',
    'port':27017,
    'database':'sns_mq',
    'taskmeta_collection':"sns_taskmeta_collection",
}
CELERY_QUEUES = {"user":{
                "exchange":"user",
                 "exchange_type":"direct",
                    "binding_key":"user"
            },
          "other":{
                "exchange":"other",
                "exchange_type":"direct",
                "binding_key":"other",            
            }
        }


CELERY_ROUTES = {
    "
Tasks.user":{
        "queue":"user",
        "routing_key":"user"
    },
    "
Tasks.test":
    {
        "queue":"other",
        "routing_key":"other"
    }
}


Tasks/user.py:
from celery.task import task
from mongoengine import *
'''
注意:
任务定义可以是通过task装饰的函数也可以是继承至Task的类。
任务实例化只进行一次,实例化完成后将被注册到全局任务表,
也就是说当任务是Python类时,每个进程中类的__init__构造函数
只执行一次,从语义上而言任务类更接近于Actor。这个特点可用于
缓存各种资源,比如数据库连接。
task装饰器可以有多个参数,这些参数对应于Task类的类成员变量,
比如任务的重试次数,重试handler都可在Task子类中重载。因此在生产
环境中的多数任务推荐用类的方式。具体细节可参考官方文档。
http://ask.github.com/celery/userguide/tasks.html
演示代码简便起见用函数的形式。

'''
connect('Proj',host='192.168.1.102',port=27017,max_pool_size=20)
from Proj.sns_users.docs import UserCache

@task
def get_all_record():
    return list(UserCache.objects.all())


在celeryconfig.py所在目录下运行celeryd -l INFO -Q user, other
celeryd的守护进程运行方式脚本可参考官方文档

6、服务器B
celeryconfig.py
BROKER_HOST = "192.168.1.102"
BROKER_PORT = 5672
BROKER_USER = 'sns'
BROKER_PASSWORD = "sns"
BROKER_VHOST = "sns_host"
CELERY_RESULT_BACKEND = "mongodb"
CELERY_MONGODB_BACKEND_SETTINGS = {
    'host':'192.168.1.102',
    'port':27017,
    'database':'sns_mq',
    'taskmeta_collection':"sns_taskmeta_collection",
}


在celeryconfig.py所在目录下运行python
>> from celery.execute import send_task
>>r = send_task("Task.user.get_all_record",routing_key = 'user', queue='user')
>>r.ready()
True
>>r.result
...


五、一些说法
Celery 不是“只支持Python“,它采用Workhook的形式和其他语言、平台进行协作 —— 个人观点这比gearman的多语言支持方法更好。Celery其实只是一个协议,celeryd恰巧是python写的~,仅次而已。、


六 、celery中的Map/Reduce
 从某种程度上而言,Celery是支持Map/Reduce的,对应的celery功能称为Tasksets和Chords。比如:
任务:task.py
from celery.task import task@taskdef add(x, y):    return x + y@taskdef tsum(numbers):    return sum(numbers)可以用以下方法实现map/reduce:>>> from celery.task import chord>>> from tasks import add, tsum>>> chord(add.subtask((i, i))...     for i in xrange(100))(tsum.subtask()).get()9900当然由于同步和消息传递上的开销这段代码的效率没有sum(i + i for i in xrange(100))高。同步是一种非常耗时的工作(chord等待所有任务的完成),因此如果不是特别必要应该尽量减少chords的使用。当然,在多数并行计算算法中同步又不必不可少的。默认情况下,同步是这样实现的:chord每秒都在不断taskset的完成状况,当taskset完成后调用callback子任务。
0 0
原创粉丝点击