celery配合rabbitmq任务队列实现任务的异步调度执行

前言:

这东西在任务调度方面,很有一套的,学习他有段时间了,自己也试图在项目中用,但苦于没有这个机会。这两天要给部门写个rest的短信接口,但是总感觉那东西时不时的会堵塞,致使其他的逻辑跑不通,所以把要发信息的这个任务放到后台异步的执行,等我想起来,再看看结果。

225401454.jpg

对于上面的场景,我曾经用tornado和gevent的方案解决,但是在我的理解范围下,感觉还是不算成熟。 tornado把任务异步后,总是影响了他的高性能。再说gevent,他是个模拟事件的东西,超好用,但是异步后,有时会出现莫名的bug,听说是gevent的1.1解决,有时间我再试试。【个人的理解有限,忘指导】


为啥要用celery ?

在我的应用下,可以把他异步到后台执行,想起来了,把他调到前面。


和rabbitmq又有啥关系?

和rabbitmq的关系只是在于,celery没有消息存储功能,他需要介质,比如rabbitmq redis mysql mongodb 都是可以的。有这个可控的东西,你也可以在库里面搞搞。推荐使用rabbitmq,他的速度和可用性都很高,redis这东西就怕意外,当然你运气很好,不怕他意外的挂掉,是可以用的。


Celery和RabbitMQ是两个层面的东西。
Celery是一个分布式的任务队列。它的基本工作就是管理分配任务到不同的服务器,并且取得结果。至于说服务器之间是如何进行通信的?这个Celery本身不能解决。
所以,RabbitMQ作为一个消息队列管理工具被引入到和Celery集成,负责处理服务器之间的通信任务。

当然,后来Celery相继增加了一些对Redis,MongoDB之类的支持。原因是RabbitMQ尽管足够强大,但对于一些相对简单的业务环境来说可能太多(复杂)了一些。这样用户可以有多一些的选择。




celery的介绍

Celery(芹菜)是一个异步任务队列/基于分布式消息传递的作业队列。它侧重于实时操作,但对调度支持也很好。

celery用于生产系统每天处理数以百万计的任务。


celery是用Python编写的,但该协议可以在任何语言实现。它也可以与其他语言通过webhooks实现。


建议的消息代理RabbitMQ的,但提供有限支持Redis, Beanstalk, MongoDB, CouchDB, ,和数据库(使用SQLAlchemy的或Django的 ORM) 。


celery是易于集成Django, Pylons and Flask,使用 django-celery, celery-pylons and Flask-Celery 附加包即可。

官方说,他们在用 ~

074432221.jpg

安装:

1
pip install celery

编译安装

1
2
3
4
tar xvfz celery- 0.0 . 0 .tar.gz
cd celery- 0.0 . 0
python setup.py build
python setup.py install #  as  root


065314742.jpg

对于消息的存储方案,可以用rabbitmq也可以用redis。 要是不重要的数据,我个人会用redis,毕竟这东西,我比较熟悉。

1
yum -y install rabbitmq-server


不嫌麻烦,就编译:

1
2
3
4
$ tar xvzf rabbitmq-server- 2.6 . 1 .tar.gz
$ cd rabbitmq-server- 2.6 . 1
$ make
# TARGET_DIR=/usr/local SBIN_DIR=/usr/local/sbin MAN_DIR=/usr/local/man make install

编译完了后

1
rabbitmqctl  rabbitmq-env  rabbitmq-server


这样子就安装成功了。


1
2
3
4
5
6
运行
找到sbin/目录,运行程序:
/usr/local/sbin/rabbitmq-server –detached
停止程序:
/usr/local/sbin/rabbitmqctl stop
rabbitmqctl  rabbitmq-env  rabbitmq-server


我们可以看看他的状态:

070846664.jpg


要是喜欢用redis,那就需要安装 celery redis相应的模块 !

071101794.jpg

celery启动配置文件:

1
2
3
4
5
6
7
8
9
10
11
#coding:utf-8
import  sys
import  os
sys.path.insert( 0 , os.getcwd())
CELERY_IMPORTS  =  ( "tasks" , )
CELERY_RESULT_BACKEND  =  "amqp"
BROKER_HOST  =  "localhost"
BROKER_PORT  =  5672
BROKER_USER  =  "guest"
BROKER_PASSWORD  =  "guest"
BROKER_VHOST  =  "/"


启动下:

071338233.jpg

咱们看看他的信息:

071415903.jpg


一个简单的测试,这个模块里面的内容也就是需要异步起来的任务。

1
2
3
4
5
6
from celery.task  import  task
import  time
@task()
def add(x, y):
     time.sleep( 5 )
     return  x + y


我们来测试下 ~

071758381.jpg


大家有注意那个False吗? 为啥会出现,因为我的tasks.py里面定义了让他sleep 5秒钟,我马上要数据,肯定是没有的,等5秒过了后,我再去提取数据,就可以了。

072121513.jpg


再特定的情况下,结果只能是上次的结果的。


这个是他的工作日志

072258574.jpg


详细的一个步骤流程:

1
2
3
4
5
6
7
8
9
10
11
In [ 1 ]: from main.tasks  import  add
In [ 2 ]: a=add.delay( 1 , 1 )
In [ 3 ]: a.ready() #worker未开启
Out[ 3 ]: False
In [ 4 ]: a=add.delay( 1 , 1 ) #开启worker,重新执行
In [ 5 ]: a.ready()
Out[ 5 ]: True
In [ 9 ]: a. get () #Waits until the task  is  done and returns the retval.
Out[ 9 ]:  2
In [ 10 ]: a.successful()
Out[ 10 ]: True

celery的参数众多的 ~

你可以等待结果来完成,但这不是因为它的异步调用同步使用

result.get(timeout=1)

但是这东西经常出问题,下图就是


075428138.jpg

咱们可以让他返回json串

1
2
3
4
5
6
7
app.conf.update(
     CELERY_TASK_SERIALIZER = 'json' ,
     CELERY_ACCEPT_CONTENT = [ 'json' ],   # Ignore other content
     CELERY_RESULT_SERIALIZER = 'json' ,
     CELERY_TIMEZONE = 'Europe/Oslo' ,
     CELERY_ENABLE_UTC = True ,
)


咱们再来说说redis的执行方式:

1
2
3
4
5
6
7
8
9
10
redis的方法
# tasks.py
import  time
from celery  import  Celery
import  os
celery = Celery( 'tasks' , broker= 'redis://localhost:6379/0' )
@celery.task
def osrun(good):
     reok=os.popen(good).read()
     return  reok


再一个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from celery  import  Celery
try :
     import  context_init
except ImportError:
     from queue  import  context_init
import  settings
from test  import  *
BROKER =  'redis://127.0.0.1:6379/1'
celery = Celery( 'tasks' , broker=BROKER)
@celery.task
def test():
     result =  1  1
     return  result
@celery.task
def test2(a, b):
     result = a + b
     return  result

启动celery

1
celery -A tasks worker --loglevel=info


为了方便我们执行celery后端进程,我们可以他把注册为服务。

/etc/default/celeryd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Name of nodes to start, here we have a single node
CELERYD_NODES= "w1"
# or we could have three nodes:
#CELERYD_NODES= "w1 w2 w3"
# Where to chdir at start. (CATMAID Django project dir.)
CELERYD_CHDIR= "/path/to/CATMAID/django/projects/mysite/"
# Python interpreter from environment. ( in  CATMAID Django dir)
ENV_PYTHON= "/path/to/CATMAID/django/env/bin/python"
# How to call  "manage.py celeryd_multi"
CELERYD_MULTI= "$ENV_PYTHON $CELERYD_CHDIR/manage.py celeryd_multi"
# How to call  "manage.py celeryctl"
CELERYCTL= "$ENV_PYTHON $CELERYD_CHDIR/manage.py celeryctl"
# Extra arguments to celeryd
CELERYD_OPTS= "--time-limit=300 --concurrency=1"
# Name of the celery config module.
CELERY_CONFIG_MODULE= "celeryconfig"
# %n will be replaced  with  the nodename.
CELERYD_LOG_FILE= "/var/log/celery/%n.log"
CELERYD_PID_FILE= "/var/run/celery/%n.pid"
# Workers should run  as  an unprivileged user.
CELERYD_USER= "celery"
CELERYD_GROUP= "celery"
# Name of the projects settings module.
export DJANGO_SETTINGS_MODULE= "settings"


加个用户,以后就可以 service celeryd start启动了

1
adduser --system --no-create-home --disabled-login --disabled-password --group celery


总结:

以后有他,我再也不怕堵塞了。但是我对他的理解还是有限,后期再更新下高级方面的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值