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

renwofei423 发布于 2011/07/29 10:09
阅读 9K+
收藏 18

  • RabbitMQ大家应该不陌生,著名的消息队列嘛。可惜我最近才听说它的大名,了解之后不禁惊呼,世界上居然还有这种东西! 立刻觉得手里有了锤子,就看什么都是钉子了,主网站不愿意干的操作统统扔给RabbitMQ去做吧 

    言归正传,先介绍一下这篇文章的应用场景吧。我们知道大型网站的性能非常重要,然而有时不得不做一些相当耗时的操作。 比如SNS网站的“新鲜事儿”系统,我发帖之后,会给所有关注我的人推送一条通知。乍一看没什么难的,发帖之后找出关注我的人, 然后生成相应的消息记录就行了。但问题是,100个人关注我,就要执行100条INSERT查询,更要命的是,Web服务器是同步的, 这100条查询执行完成之前,用户是看不到结果的。

    怎么办呢,这时就轮到消息队列上场了。发帖之后只需给队列发送一条消息, 告诉队列“我发帖子了”,然后把发帖的结果返回给用户。 这时另一个叫做worker的进程会取出这条消息并执行那100条INSERT查询。这样,推送通知的操作在后台异步执行, 用户就能立即看到发帖结果。更精彩的是,可以运行多个worker实现分布式,多繁重的任务都不在话下了。

    好了,来看看今天的主角:

    • django:web框架,其实只能算作配角了;
    • RabbitMQ:消息队列系统,负责存储消息;
    • celery:worker进程,同时提供在webapp中创建任务的功能。
    django-celery-rabbitmq-intro-1.png

    安装

    安装环境是MacOS,使用其他操作系统的同学请自行调整安装命令。

    django的安装配置就不说了,配角嘛。

    先来安装RabbitMQ:

    $ sudo port install -n rabbitmq

    启动RabbitMQ:

    $ sudo rabbitmq-server -detached

    然后安装celery。到 http://pypi.python.org/pypi/celery#downloads 下载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这个模块。 到 http://pypi.python.org/pypi/django-celery#downloads 下载 django-celery 并安装:

    $ 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,如有需要请自行下载编译。

    应用程序示例

    建立测试应用程序:

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

    然后修改settings.py,在INSTALLED_APPS中加入以下内容:

    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要用到数据库的。配置好之后执行:

    $ 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解放出来吧。

加载中
0
nicozhang
nicozhang
大神,请教个问题。虽然这篇文章已经很久了。我想用celery和rabbitmq实现一个定时执行的功能,这个地方要用哪个函数,及参数要用哪些?
renwofei423
renwofei423
抱歉,这个很久没有用了,忘记了。 建议搜索下,或者看看官方文档吧。
0
nicozhang
nicozhang
看了官方的api文档,就没发现它有这个功能:间隔定时执行某个程序。
0
ajmdfeipan
ajmdfeipan
http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html
0
renwofei423
renwofei423

引用来自“ajmdfeipan”的评论

http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html
@nicozhang
返回顶部
顶部