Celery分布式实践

Celery3.1.7文档:http://docs.jinkan.org/docs/celery/index.html

Celery4.4.0文档:http://docs.celeryproject.org/en/master/index.html

基本的Celery执行任务分发实现在我的另一篇博文“Celery学习记录”已有描述,这里不再赘述。

一、基本文件的创建与配置

这里配置在windows或者是linux中均可。甚至可以有的节点为windows有的节点为linux,不冲突。

上图是我的项目的文件路径及项目包含的文件:"celery_config.py,celery.py, __init__.py, tasks.py"。

(1)__init__.py

用于标识当前文件夹为一个python package。文件内容为空。

(2)celery.py

用于定义app:

# -*- coding:utf-8 -*-
from __future__ import absolute_import
from celery import Celery

app = Celery('proj', )   # include=['proj.tasks']
app.config_from_object('proj.celery_config')


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

(3)celery_config.py

配置文件。

# -*- coding:utf-8 -*-
# from __future__ import absolute_import
from kombu import Exchange, Queue

BROKER_URL = 'redis://****:6379/3'  # broker
CELERY_RESULT_BACKEND = 'redis://*****:6379/4'  # 存储任务状态和结果

CELERY_IMPORTS = ('proj.tasks', )    # 开始时要导入的模块列表

CELERY_TASK_SERIALIZER = 'json'  # 任务序列化和反序列化    pickle

CELERY_RESULT_SERIALIZER = 'json'  # 结果序列化格式,默认为pickle

CELERY_ACCEPT_CONTENT = ['json']  # 指定接受的内容类型(默认为允许所有格式)   ['pickle', 'json', 'msgpack', 'yaml']
CELERY_ENABLE_UTC = True
CELERY_TIMEZONE = 'Asia/Shanghai'

CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24  # 任务过期时间

# ---------------------定义路由、交换、队列------------------------

CELERY_DEFAULT_QUEUE = 'default'
CELERY_QUEUES = (
    Queue('default', Exchange('default'), routing_key='default'),
    Queue('add', Exchange('add'), routing_key='add'),
    Queue('multi', Exchange('multi'), routing_key='multi'),
)
CELERY_DEFAULT_EXCHANGE = 'default'
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
CELERY_DEFAULT_ROUTING_KEY = 'default'

其中,BROKER_URL、CELERY_RESULT_BACKEND分别对应于你实际使用的中间人broker与结果存储后端backend,我这里使用的是redis。CELERY_QUEUES中包含的Queue为定义的队列,目的是用于实现在不同的节点上执行不同的任务,如果不需要区分不同的节点,则无需设置与Queue、Exchange、Routing相关的项。具体这几项设置的含义,参见Routing Tasks(文档)。

(4)tasks.py

定义用于执行的任务:

# -*- coding:utf-8 -*-
from __future__ import absolute_import
import time
from proj.celery import app


@app.task
def add(x, y):
    print "this is the add function..."
    time.sleep(1)
    return x+y


@app.task
def multi(x, y):
    print "this is the multi function..."
    time.sleep(1)
    return x*y

最后,复制上述代码到另一个服务器节点,这里我的另一个节点为windows环境。 

理论上,可以有任意多个节点。

二、启动Broker及Backend

broker及backend能够正常运行、通信,是celery运行的必须条件。

这里我用的是redis,下载安装及配置在博文Celery学习记录都有,不再赘述。

根据配置进行启动: /usr/local/redis-4.0.11/src/redis-server    /usr/local/redis-4.0.11/redis.conf

三、发布任务

1、简单实现分布式,不区分节点执行的任务内容

首先,在linux(centos)下,执行 celery -A proj worker -l info  启动任务监听。

 在windows下启动任务监听:

可以看到后启动的windows监视窗口,输出显示有一个neighbors节点,即我们先启动的linux节点。这时,你再去观察先开启的linux下的窗口同样出现了

类似的消息,表示有新的节点加入到了集群中。 

现在,可以在python环境,或者写一个py文件来执行文件,这里我写了一个py文件,如下:

# -*- coding:utf-8 -*-
from proj.tasks import add, multi


for i in range(10):
    re1 = add.apply_async(args=[i, i])   # 调用add task
    re2 = multi.apply_async(args=[i, i])  # 调用 multi task
    re1.get()
    re2.get()

 注意,这个py文件应该放在proj 的同级文件夹下,不是proj中。这里,我是循环调用了add和multi方法。可以在windows或者linux任意一个节点中run均可"python 文件名.py",不妨这里就叫a.py

效果如下:

linux监视窗口:

 windows环境下的监视窗口:

 不难发现,两个节点均执行了add和multi函数,没有加以区分,并且混合出现。

2、每个节点执行指定队列的任务

只需要在启动Celery服务时,加上“-Q”参数(前提是已经在配置文件celery_config.py中定义好了队列),-Q参数指明了当前节点要监视、执行的任务队列。

根据定义好的队列,启动Celery服务:

(1)启动linux节点的Celery服务:

celery -A proj worker -l info -Q add

 注意,这里启动后console中显示的输出日志,包含了queues,其内容与我们定义及启动的队列相一致。

(2)启动windows节点的Celery服务:

celery -A proj worker -l info -Q multi

 (3)发布任务

修改我们先前写的a.py:

# -*- coding:utf-8 -*-
from proj.tasks import add, multi


for i in range(10):
    re1 = add.apply_async(args=[i, i], queue='add', routing_key='add')
    re2 = multi.apply_async(args=[i, i], queue='multi', routing_key='multi')
    #  或者写为:re2 = multi.apply_async(kwargs={'x': i, 'y': i}, queue='multi', routing_key='multi')
    re1.get()
    re2.get()

注意,发布任务时,指明了任务所要发布到的队列及队列的密匙(参见:Routing Tasks)。

观察linux及windows节点的Celery监控日志,发现:linux节点只执行了add任务,windows节点只执行了multi任务,与我们发布的任务队列一致。

linux:

 windows:

 注意:在配置文件中我还定义了一个“default”队列,发布任务时并没有用到,当然这个队列可以选择去掉或者保留。并且,每一个节点可以执行的任务队列可以为多个只需在-Q参数后用英文 “,” 隔开即可。例如:celery -A proj worker -l info -Q multi, default。这个default队列的另一个作用是,当有任务没有被指定队列时,则默认分配到default队列中。 

3、通过配置文件将任务绑定到指定的队列

修改配置文件 celery_config.py :

# -*- coding:utf-8 -*-
# from __future__ import absolute_import
from kombu import Exchange, Queue

BROKER_URL = 'redis://****:6379/3'  # broker
CELERY_RESULT_BACKEND = 'redis://*****:6379/4'  # 存储任务状态和结果

CELERY_IMPORTS = ('proj.tasks', )    # 开始时要导入的模块列表

CELERY_TASK_SERIALIZER = 'json'  # 任务序列化和反序列化    pickle

CELERY_RESULT_SERIALIZER = 'json'  # 结果序列化格式,默认为pickle

CELERY_ACCEPT_CONTENT = ['json']  # 指定接受的内容类型(默认为允许所有格式)   ['pickle', 'json', 'msgpack', 'yaml']
CELERY_ENABLE_UTC = True
CELERY_TIMEZONE = 'Asia/Shanghai'

CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24  # 任务过期时间

# ---------------------定义路由、交换、队列------------------------
# http://docs.jinkan.org/docs/celery/userguide/routing.html
CELERY_ROUTES = ({'proj.tasks.add': {
                        'queue': 'add',
                        'routing_key': 'add'
                 }}, )

CELERY_DEFAULT_QUEUE = 'default'
CELERY_QUEUES = (
    Queue('default', Exchange('default'), routing_key='default'),
    Queue('add', Exchange('add'), routing_key='add'),
    Queue('multi', Exchange('multi'), routing_key='multi'),
)
CELERY_DEFAULT_EXCHANGE = 'default'
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
CELERY_DEFAULT_ROUTING_KEY = 'default'

 注意,此部分修改的内容为增加了CELERY_ROUTES参数:

 

 修改发布任务的a.py:

即,将add函数的queue及routing_key去掉(使用配置文件的绑定设置)。

重启各节点的Celery服务,并在任意一个节点运行python a.py。观察结果:

(1)使用celery -A proj worker -l info -Q add 启动的节点:

(2)使用 celery -A proj worker -l info -Q multi 启动的节点: 

 

此部分与上部分“2”很相近。不同的是“2”是指定了几个队列,每个节点监听不同的队列,任务分发的时候需要将任务通过

apply_async(args=, queue='', routing_key='')

方法指定到特定的队列中去。而本部分,可以通过直接将任务绑定到指定的任务队列,任务发布时无需再指定队列,即使用 apply_async 方法时,不需要queue及routing_key参数。 

附:

可以在浏览器窗口查看任务执行情况,方法是在开启新的命令窗口执行“celery flower --broker=你的实际broker设置”,然后根据输出提示,访问http://localhost:5555,当然也可以使用“--port=5555” 指定端口。方法参见:Monitoring and Management Guide

效果图: 

 

 

推荐阅读(其实最好还是去看一遍官方文档):

celery#集群管理实现

CELERY 集群管理实现

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值