使用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解放出來吧。


批註:最後一段不敢苟同,我以爲消息隊列仍是很可靠的,處理關鍵任務也應該是沒問題,作好日誌和任務信息備份,照樣能夠很穩定的運行。

相關文章
相關標籤/搜索