簡單的例子
在使用 Celery 的過程中主要的步驟如下:
- 定義一個應用,並在應用上註冊任務;
- 啓動 worker,通過消息隊列等待任務;
- 通過在程序裏調用預先註冊的任務給 Celery 提交一個任務。
tasks.py 包含了一個簡單的示例,來自於Celery的官方文檔,主要進行了任務的註冊,首先創建了一個 Celery 實例 app,這是 Celery 裏的一個應用(Application),第一個參數是應用 名,Celery 的 worker 通過這個名字尋找應用;第二個參數是 broker 這裏設置爲本機的Redis Server。然後通過 app.task 裝飾器爲 app 這個應用註冊一個任務。
#tasks.py
from celery import Celery
app = Celery('tasks',broker="redis://127.0.0.1:6379/0")
@app.task
def add(x,y):
return x + y
然後可以通過如下命令啓動 worker, 其中 -A 參數用於指定在 tasks.py 裏定義的應用的名字,–loglevel (等同於-l)用於指定日誌的記錄等級
celery -A tasks worker -l info
應該會看到一個大致這樣的啓動界面,下面解釋下 [config] 的大致含義,其中 app 是 worker 對應的應用名,transport 是指在前面制定的消息隊列地址,results 是指 任務執行結果存儲的地方,但是這裏沒有指定,所以默認就是關閉的。concurrency 是 worker 的數量,默認和處理器的核心數相同。
然後啓動另外一個終端,進入python工作環境,執行任務,如下圖所示:
調用delay函數即可啓動add這個任務,add函數的參數爲4,4,這個函數的效果是發送一條消息到broker中去,這個消息包括要執行的函數已經執行函數的參數,還有一些其他信息,具體的可以看Celery的文檔。
因爲之前已經啓動了一個worker,這個worker會等待broker中的消息,一旦收到消息就會立刻執行消息。
啓動了一個任務之後,可以看到之前啓動的worker已經開始執行任務了。效果如下圖所示:
從上圖中可以看到,任務已經被執行成功。
添加backend
Celery5.0起就不在支持amqp作爲backend了,所以選擇用RabbitMQ 作爲broker,用redis作爲backend。
安裝RabbitMQ :參考Celery學習筆記(一)
安裝redis服務器
linux安裝
1.Download, extract and compile Redis with:
$ wget http://download.redis.io/releases/redis-3.2.8.tar.gz
$ tar xzf redis-3.2.8.tar.gz
$ cd redis-3.2.8
$ make
2.The binaries that are now compiled are available in the src directory. Run Redis with:
$ src/redis-server --protected-mode no
注意:開啓服務器的時候指定 –protected-mode no,否則運行時會出錯。
3.You can interact with Redis using the built-in client:
$ src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"
運行broker的機器上安裝redis支持
對 Redis 的支持需要額外的依賴。你可以用 celery[redis] 捆綁 同時安裝 Celery 和這些依賴:
pip install -U celery[redis]
或者 pip install "celery[librabbitmq,redis,msgpack]"
配置
#!/usr/bin/env python
# encoding: utf-8
from __future__ import absolute_import
from celery import Celery
app=Celery('myapp',broker='amqp://danny:[email protected]:5672/myvhost',backend='redis://192.168.1.128:6379/0',
include=['myapp.agent'])
app.config_from_object('myapp.config')
if __name__ == '__main__':
app.start()
獲得任務的返回值
>>> res=add.delay(1,2)
>>> res.status
u'SUCCESS'
>>> res.get()
{u'value': u'3', u'node_name': u'docker1'}
Celery的一些配置
Celery的分佈式實際包含兩個層次:
- Distribute work on a given machine across all CPUs
- Distribute work to many machines
先說第一點,默認情況下,Celery在一臺機器上啓動worker,worker的進程數量和機器的CPU個數一致。但也可以通過concurrency參數控制啓動worker的進程數量:
同時啓動5個worker進程
celery -A tasks worker --loglevel=INFO --concurrency=5
比如你的機器只有一個CPU,但仍然可以通過上述方法啓動5個worker進程,在某些IO密集型的任務中,可以考慮啓動worker的數量多於CPU數量,在CPU密集型的任務中,這樣的操作可能沒有什麼好處。
再說第二點,因爲Celery只指定了worker的broker,所以只需要在不同機器上啓動worker,它們都會從相同的broker中獲取任務並處理。
在考慮不同機器上的操作時,涉及遠程控制的概念。
celery inspect
觀察所有運行worker的信息,例如觀察當前處於活躍狀態的worker和task:
celery -A tasks inspect active
celery control
控制worker的行爲,例如向worker中增加對某隊列的消費:
celery control -d w1.e.com add_consumer queue_name
celery status
觀察當前worker狀態
celery -A tasks status
# celery@iZ25d0yvrwwZ: OK
#
# 1 node online.
可見性超時
可見性超時時間定義了等待職程在消息分派到其他職程之前確認收到任務的秒數
這個選項通過 BROKER_TRANSPORT_OPTIONS 設置:
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600} # 1 hour.
Redis 的默認可見性超時時間是 1 小時
如果任務沒有在 可見性超時 內確認接收,任務會被重新委派給另一個職程並執行。所以你需要增大可見性超時時間,以符合你計劃使用的最長預計到達時間。
注意 Celery 會在職程關閉的時候重新分派消息,所以較長的可見性超時時間只會造成在斷電或強制終止職程之後“丟失”任務重新委派的延遲。
你可以配置同名的傳輸選項來增大這個時間:
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 43200}
這個值必須是整數,單位是秒。