最近大Boss反饋Celery常常出現問題,幾經實踐終於把問題解決了!因而乎有了這篇博客的誕生,算是一個實踐經驗的分享吧!css
軟件版本以下:html
Celery (4.1.0) Flask (0.12.1) RabbitMQ(3.6.9) librabbitmq (1.6.1)
介紹
簡單來講Celery是一個異步的任務隊列,當咱們須要將一些任務(好比一些須要長時間操做的任務)異步操做的時候,這時候Celery就能夠幫到咱們,另外Celery還支持定時任務(相似Crontab)。詳細的介紹能夠參考官網python
使用RabbitMQ做爲Broker
RabbitMQ是官方推薦使用的Broker,它實際是一個消息中間件,負責消息的路由分發,安裝RabbitMQ以下:redis
# install on Ubuntu apt-get update apt-get install rabbitmq-server -yq
須要注意的是,線上環境咱們須要建立新的帳號,並將guest帳號刪除,操做以下:shell
rabbitmqctl add_user myuser mypassword # 新增用戶 rabbitmqctl add_vhost myvhost # 新增vhost,以使用不一樣的命名空間 rabbitmqctl set_permissions -p myvhost myuser ".*" ".*" ".*" # 設置權限 rabbitmqctl delete_user guest # 安全緣由,刪除guest
注意:vhost是一個虛擬空間,用於區分不一樣類型的消息
而後,在Celery的配置中配置broker URL:數據庫
CELERY_BROKER_URL = 'amqp://myuser:mypassword@localhost:5672/myvhost'
注意:當使用amqp協議頭時,若是安裝有librabbitmq
則使用librabbitmq
,不然使用pyamqp後端
Celery的日誌輸出
在task中想要輸出日誌,最好的方法是經過以下方式:緩存
from celery.utils.log import get_task_logger lg = get_task_logger(__name__) @celery.task def log_test(): lg.debug("in log_test()")
可是僅如此會發現全部的日誌最後都跑到shell窗口的stdout當中,原來必須得在啓動celery的時候使用-f option來指定輸出文件,以下:安全
celery -A main.celery worker -l debug -f log/celery/celery_task.log &
-A:指定celery實例
worker: 啓動worker進程
-l:指定log level,這裏指定log level爲debug level
-f:指定輸出的日誌文件bash
使用Redis做爲backend
當使用Redis做爲存儲後端的時候,咱們能夠經過設置DB number來使得Celery的結果存儲與其它數據存儲隔離開來,好比在筆者的項目中,redis還用做緩存的存儲後端,所以爲了區分,Celery在使用Redis的時候使用的DB number是1(默認是0),關於Redis DB number能夠參考這裏.
所以咱們的backend設置以下:
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1' # 最後的數字1表明DB number
查看Celery任務的結果能夠經過Redis-cli鏈接Redis數據庫進行查看:
> redis-cli > select 1 # 這裏選擇DB 1, 也能夠在使用redis-cli -n 1來進入指定的DB > get key # 獲取指定key對應的結果
Celery可能會遇到的坑
Celery4.x版本使用librabbitmq的問題
Celery 4.x版本在使用librabbitmq時,會出現相似這樣的錯誤
Received and deleted unknown message. Wrong destination?!?
解決這個問題有兩個方式:
- 推薦方式,更改配置項task_protocol爲1。
Github上Robert Kopaczewski詳細解釋了這個問題,原文以下:
Apparently librabbitmq issue is related to new default protocol in celery 4.x. You can switch to previous protocol version by either
putting CELERY_TASK_PROTOCOL = 1 in your settings if you're using Django or settings app.conf.task_protocol = 1 in celeryconf.py.
- 另外一種方式是不使用librabbitmq, 經過pip uninstall librabbitmq, 而且更改broker配置的協議頭爲'pyamqp',以下,也能夠解決這個問題。
BROKER_URL = 'pyamqp://guest:guest@localhost:5672/%2F'
因爲librabbitmq的性能優點,咱們仍是推薦方式1來解決該問題。
RabbitMQ遠程鏈接問題
若是RabbitMQ與Celery不在同一臺機器上,除在Celery配置的時候要將BROKER_URL
設置爲正確的IP地址外,還須要將Rabbitmq的配置文件/usr/local/etc/rabbitmq/rabbitmq-env.conf
中的NODE_IP_ADDRESS
更改成0.0.0.0
NODE_IP_ADDRESS=0.0.0.0
Celery import問題
The message has been ignored and discarded. Did you remember to import the module containing this task? Or maybe you're using relative imports? Please see http://docs.celeryq.org/en/latest/internals/protocol.html for more information. The full contents of the message body was: '\x8e\xa7expires\xc0\xa3utc\xc3\xa4args\x91\x85\xa3tid\xb85971a43d47f84bb278f77fc2\xa3sen\xa2A1\xa2tt\xa2ar\xa2co\xc4\x00\xa1t\xa4like\xa5chord\xc0\xa9callbacks\xc0\xa8errbacks\xc0\xa7taskset\xc0\xa2id\xc4$c133dbf8-2c89-4311-b7cf-c377041058ec\xa7retries\x00\xa4task\xd9$tasks.messageTasks.send_like_message\xa5group\xc0\xa9timelimit\x92\xc0\xc0\xa3eta\xc0\xa6kwargs\x80' (239b) Traceback (most recent call last): File "/Users/liufeng/.pyenv/versions/2.7.13/envs/kaopu_backend/lib/python2.7/site-packages/celery/worker/consumer/consumer.py", line 561, in on_task_received strategy = strategies[type_] KeyError: u'tasks.messageTasks.send_like_message'
出現這條錯誤是因爲咱們的tasks跟celery並非在同一個文件中,即不是同一個module,當咱們經過以下命令啓動task worker時,實際只加載了app module,而沒有加載tasks相關的module
celery -A app.celery worker -l info
要解決這個問題,必須爲celery配置文件添加import參數,以下
app.config['imports'] = ['tasks.messageTasks']
Celery unregistered task問題
在開發過程當中遇到了這樣一個問題:
[2018-03-31 15:38:19,605: ERROR/MainProcess] Received unregistered task of type u'app.tasks.messageTasks.send_follow_message'. The message has been ignored and discarded. Did you remember to import the module containing this task? Or maybe you're using relative imports? Please see http://docs.celeryq.org/en/latest/internals/protocol.html for more information. The full contents of the message body was: '\x8e\xa7expires\xc0\xa3utc\xc3\xa4args\x91\x86\xa6sender\xa5Jenny\xa9target_id\xb859a5313847f84be534ad7d46\xabtarget_type\xa4user\xa7content\xc4\x00\xa8receiver\xb859a5313847f84be534ad7d46\xa4type\xa6follow\xa5chord\xc0\xa9callbacks\xc0\xa8errbacks\xc0\xa7taskset\xc0\xa2id\xc4$a4d40c14-1976-41a6-a753-d2a495929920\xa7retries\x00\xa4task\xd9*app.tasks.messageTasks.send_follow_message\xa5group\xc0\xa9timelimit\x92\xc0\xc0\xa3eta\xc0\xa6kwargs\x80' (312b) Traceback (most recent call last): File "/Users/liufeng/.pyenv/versions/2.7.13/envs/kaopu_backend/lib/python2.7/site-packages/celery/worker/consumer/consumer.py", line 561, in on_task_received strategy = strategies[type_] KeyError: u'app.tasks.messageTasks.send_follow_message'
解決這個問題,最開始是根據提示,將全部涉及到task的module所有加上from __future__ import absolute_import
以後運行以後仍是不行,後來發現是因爲以前啓動時使用的是app module, 可是個人代碼已經改爲了main.py,因此從新啓動了celery,最後問題解決
使用鏡像遷移系統也依然須要從新添加rabbitmq的用戶
問題最開始是發現沒法點贊,也沒法Follow用戶,經過http消息發現出現502錯誤,因而登陸到服務器檢查,發現應用服務自己沒有任何報錯,因而又去查看Celery的日誌,結果發現出現以下錯誤:
[2018-03-31 16:32:01,243: ERROR/MainProcess] consumer: Cannot connect to amqp://celeryuser:**@loc alhost:5672/celeryvhost: Couldn't log in: a socket error occurred.
通過一番搜索發現網上的評論主要是說URL不對的狀況下會出現這種狀況,可是個人URL沒有改過啊,那又會是什麼問題呢?繼續看,發現有人提到了權限問題,因而又是一番檢查,發現RabbitMQ中並無原先設置的用戶(我使用的是原系統的鏡像,原覺得用戶也是已經設置好的)
# 查看有哪些用戶 rabbitmqctl list_users
而後就簡單了,按照步驟建立用戶,vhost,再賦予權限,刪除guest,而後就終於都連好了
另外,發現從鏡像複製系統後,RabbitMQ並不能正常工做,必須殺掉原先的進程,從新啓動
更改task的代碼後,重啓Celery
須要注意的是,在更改task的代碼後,必須從新啓動Celery,不然代碼改動沒法生效,可能致使一些意外的問題
以上就是筆者使用過程當中的一些坑,經驗有限,若是有錯漏還請指正!不要看格式啦,由於之間都是習慣寫印象筆記,因此大家就將就着看吧!