Celery 运行在不同的server上

1.基本概况

近期项目进行横向拓展会用到celery,于是开始研究celery的手册。在看手册的过程中发现,基本所有的官方例子都是运行在一台设备上,按照例子很容易就调通了。但实际的运行环境中肯定是部署在不同的设备上。那么如何部署在两个设备上呢?

2. 开始研究

  • 运行环境:
    2台ubuntu虚拟机,网段分别为(192.168.140.100和192.168.140.101)
    celery+rabbitMQ
  • 代码环境:
    (1)celery_master.py
#! /usr/bin/env python
# -*-coding:utf-8 -*-
import time
from celery import Celery
app = Celery('celery_worker', broker='amqp://guest@localhost//', backend='amqp://guest@localhost//')    

这里构建了一个celery中的application,其中broker采用本地rabbitMQ,账户为guest账户。这里的第一个参数要指定woker的名称。
PS: 这里特别需要注意第一个参数,这个参数为__main__

main
原手册地址
Name of the __main__ module. Required for standalone scripts.
If set this will be used instead of __main__ when automatically generating task names.

根据这段话,其实说明白点就是要执行具体任务的入口函数的地址,这里相当于执行celery_worker.__main__。 这里有个问题,如果你使用的是task.delay,这种方式,则必须指定这个celery为‘celery_worker’,告诉系统执行的是‘celery_worker’中的add。这块其实感觉比较混乱,总之,就是你要让任务找到它的执行空间就行。如果你采用send_task去完成这个任务,这块你的两个app对象的第一个参数就不需要如此考究了,因为你可以在send_task指定执行的是哪个函数。
例如:

result = app.send_task('celery_worker.add', [1, 2])  

对端的工程目录层级中包含一个‘celery_worker.py’的文件,里面有个add的函数。
这里推荐使用‘send_task’这种做法,这里为了展示Celery类实例化时候的第一个参数__main__的作用,完成了这种案例(不推荐这种写法,只是说明可行)。

@app.task
def add(a, b):
    pass    

这个地方定义了一个函数,名叫add,接受两个参数,但函数体里面为pass,其实这个很重要。很多人在写celery_master和celery_work的时候把add原封不动的重新copy了一次,两个文件中都实现了add函数。但其实,将任务分发过后,具体执行的add为celery_work中的add。这里我之所以写一个pass的函数,其实相当于C语言中的函数声明,因为发送任务的时候调用了add。

while (flag):
   print app.control.ping(timeout=0.5)  # 发送ping包,看是否能访问目标地址
   result = add.delay(1, 2) # 发送具体的任务和值
   print "ID: %s" % result.id
   if result.failed():
       flag = False
   print "Flag: %s" % flag
   time.sleep(1)  

这段代码很简单,实现的功能就是每隔1分钟发送给目标worker一个任务,任务为add,参数为1、2。
(2)celery_worker.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
from celery import Celery
app = Celery('who care', broker='amqp://guest@localhost//', backend='amqp://')

这里同样构建了一个celery中的application,可以看出这里的第一个参数可以随便设置。

@app.task
def add(a, b):
    print 'Start task'
    time.sleep(3)
    print 'Finish task'
    return a + b

具体的add逻辑,这里不用多解释了吧。
以上就是整个代码的部分。
为了验证代码能正常运行,将两个代码都放到192.168.140.100设备上。然后两个终端,分别执行
celery -A celery_worker worker --loglevel=infopython celery_master.py就能看到它们在本地工作了。

3.问题来了

上面这个例子很明显和官方文档差不了多少,其实这里就是想告诉大家如何委婉的解决master和worker中关于具体任务函数该如何写,当然还有其他方法,自行研究。
现在,问题的关键在于如何在不同的设备上分开部署celery_master和celery_worker。
先说一个问题,既然要部署在不同设备上,rabbitMQ是存在账号这个说法的,之前用的guest账号只能运行在localhost下。官方有明确说明("guest" user can only connect via localhost):http://www.rabbitmq.com/access-control.html
(1)登陆192.168.140.100机器,将celery_master.py拷贝到该机器,然后执行下面操作(http://stackoverflow.com/questions/25869858/celery-error-in-connecting-to-rabbitmq-server):
现在生成一个账号密码为test、test的 rabbitMQ账号,以及一个test-vhost的virtual host。命令如下:
sudo rabbitmqctl add_user test test
sudo rabbitmqctl set_permissions -p test-vhost test ".*" ".*" ".*"
完成上诉两个步骤候开始修改代码:

app = Celery('celery_worker', broker='amqp://test:test@localhost/test-vhost', backend='amqp://')  

(2)登陆192.168.140.101机器,将celery_worker.py拷贝到该机器,然后执行下面操作:
修改代码

app = Celery('who care', broker='amqp://test:[email protected]//', backend='amqp://')

完成上述步骤后,分别在两个机器上启动对应的指令:
192.168.140.100:python celery_master.py
192.168.140.101:celery -A celery_worker worker --loglevel=info
程序就会正常运作了。

你可能感兴趣的:(Celery 运行在不同的server上)