使用django+celery+RabbitMQ实现异步执行

       RabbitMQ你们应该不陌生,著名的消息队列嘛。惋惜我最近才据说它的大名,了解以后不由惊呼,世界上竟然还有这种东西! 马上以为手里有了锤子,就看什么都是钉子了,主网站不肯意干的操做通通扔给RabbitMQ去作吧 :D
言归正传,先介绍一下这篇文章的应用场景吧。咱们知道大型网站的性能很是重要,然而有时不得不作一些至关耗时的操做。 好比SNS网站的“新鲜事儿”系统,我发帖以后,会给全部关注个人人推送一条通知。乍一看没什么难的,发帖以后找出关注个人人, 而后生成相应的消息记录就好了。但问题是,100我的关注我,就要执行100条INSERT查询,更要命的是,Web服务器是同步的, 这100条查询执行完成以前,用户是看不到结果的。
       怎么办呢,这时就轮到消息队列上场了。发帖以后只需给队列发送一条消息, 告诉队列“我发帖子了”,而后把发帖的结果返回给用户。 这时另外一个叫作worker的进程会取出这条消息并执行那100条INSERT查询。这样,推送通知的操做在后台异步执行, 用户就能当即看到发帖结果。更精彩的是,能够运行多个worker实现分布式,多繁重的任务都不在话下了。
       好了,来看看今天的主角:
               django:web框架,其实只能算做配角了;
               RabbitMQ:消息队列系统,负责存储消息;
               celery:worker进程,同时提供在webapp中建立任务的功能。python

wKiom1MAzxXw4JlZAADS8Ac8_CE458.jpg
安装
       安装环境是MacOS,使用其余操做系统的同窗请自行调整安装命令。
       django的安装配置就不说了,配角嘛。
       先来安装RabbitMQ:web

$ sudo port install -n rabbitmq

       启动RabbitMQ:shell

$ sudo rabbitmq-server -detached

       而后安装celery。到这里下载celery并安装:
数据库

$ tar xzvf celery-2.2.7.tar.gz
$ cd celery-2.2.7
$ python setup.py build
$ sudo python setup.py install

       这个过程会安装数个依赖包,包括 pyparsing、kombu、amqplib、anyjson等,若是自动安装有困难,能够自行下载编译。
       因为要在django中使用,咱们还得安装django-celery这个模块。 到这里下载 django-celery 并安装:
django

$ tar xzvf django-celery-2.2.4.tar.gz
$ cd django-celery-2.2.4
$ python setup.py build
$ sudo python setup.py install

       这个过程会安装依赖包 django-picklefield,若有须要请自行下载编译。
应用程序示例
       创建测试应用程序:
json

$ django-admin.py startproject celerytest
$ cd celerytest
$ django-admin.py startapp hello
$ cd hello

       而后修改settings.py,在INSTALLED_APPS中加入如下内容:
bash

INSTALLED_APPS = (
  ...
'djcelery',          # 加入celery
'hello',             # 测试应用程序
}

       在settings.py末尾添加RabbitMQ的配置:
服务器

import djcelery
djcelery.setup_loader()
BROKER_HOST = "localhost"
BROKER_PORT = 5672
BROKER_USER = "guest"
BROKER_PASSWORD = "guest"
BROKER_VHOST = "/"

       固然,别忘了配置数据库选项,由于djcelery要用到数据库的。配置好以后执行:
app

$ python manage.py syncdb

       能够执行 python manage.py 看一下,会发现 djcelery 应用程序给manage.py添加了许多celery*开头的命令, 这些就是控制worker的命令了。
       接下来咱们写个task。新建 hello/tasks.py,内容以下:
框架

from celery.decorators import task
@task
def add(x, y):
  return x + y

       修饰符 @task 将add函数变成了异步任务。在webapp中调用add并不会当即执行该函数,而是将函数名、 参数等打包成消息发送到消息队列中,再由worker执行实际的代码(return x + y)。
       固然,别忘了必不可少的worker:

$ python manage.py celeryd -l info

在另外一个控制台测试一下:

$ python manage.py shell
>>> from hello.tasks import add
>>> r = add.delay(3,5)     # 执行这一行就能在worker的日志中看到运行情况
>>> r.wait()
8

       能够看到,add函数是在worker上运行的,实现了异步的效果。固然,队列的特性决定了任务并非实时执行的,可能有延迟, 有时甚至还会丢失,所以,队列不适合执行关键任务。而那些执行结果无关痛痒、对实时性要求不高的任务, 就能够大胆地交给RabbitMQ去处理,将WebApp解放出来吧。


批注:最后一段不敢苟同,我以为消息队列仍是很可靠的,处理关键任务也应该是没问题,作好日志和任务信息备份,照样能够很稳定的运行。

相关文章
相关标签/搜索