Celery異步消息隊列

歡迎大家交流博客內容

什麼是Celery

celery是一個異步任務隊列/基於分佈式消息傳遞的作業隊列,分佈式隊列服務。它側重於實時操作,但對調度支持也很好。

celery用於生產系統每天處理數以百萬計的任務。

celery是用Python編寫的,但該協議可以在任何語言實現。它也可以與其他語言通過webhooks實現。

建議的消息代理RabbitMQ的,但提供有限支持Redis, Beanstalk, MongoDB, CouchDB, ,和數據庫(使用SQLAlchemy的或Django的 ORM) 。

celery是易於集成Django, Pylons and Flask,使用 django-celery, celery-pylons and Flask-Celery 附加包即可。

應用場景

  • 異步任務
    一些耗時較長的操作,如果用戶等待後臺數據返回,將會極大影響用戶體驗時,我們使用 異步消息隊列,就可以解決這個問題啦。前端可以迅速響應用戶請求,而一些異步操作則交給消息隊列去執行啦。比如發送短信/郵件、消息推送、音視頻處理等等。。
  • 定時任務:
    定時執行某件事情,比如每天數據統計
    優惠券定期刪除
    等等。。

Celery架構圖

在這裏插入圖片描述

  • Producer:調用了Celery提供的API、函數或者裝飾器而產生任務並交給任務隊列處理的都是任務生產者。
  • Celery Beat:任務調度器,Beat進程會讀取配置文件的內容,週期性地將配置中到期需要執行的任務發送給任務隊列。
  • Broker:消息代理,又稱消息中間件,Celery本身不提供消息服務,但是可以方便的和第三方提供的消息中間件集成。 接受任務生產者發送過來的任務消息,存進隊列再按序分發給任務消費方(通常是消息隊列或者數據庫)。Celery目前支持RabbitMQ、Redis、MongoDB、Beanstalk、SQLAlchemy、Zookeeper等作爲消息代理,但適用於生產環境的只有RabbitMQ和Redis, 官方推薦 RabbitMQ。
  • Celery Worker:執行任務的消費者,通常會在多臺服務器運行多個消費者來提高執行效率。
  • Result Backend:任務處理完後保存狀態信息和結果,以供查詢。Celery默認已支持Redis、RabbitMQ、MongoDB、Django ORM、SQLAlchemy等方式。

實現

  1. 準備一個項目,結構如下。
  • app.py : 實例化 Celery。
  • config.py : Celery 相關配置。
  • task.py : 任務函數文件。
  • worker.py : 執行調用任務工作。

接下來依次看一下代碼。

app.py

# -*- coding: utf-8 -*-
__author__ = 'LiuNan'
__date__ = '2020/5/22 19:52'

from celery import Celery

# app是Celery類的實例,創建的時候添加了proj.tasks這個模塊,也就是包含了proj/tasks.py這個文件。
app = Celery('Celery_project', include=['Celery_project.task'])

app.config_from_object('Celery_project.config')

if __name__ == '__main__':
    app.start()

config.py

# -*- coding: utf-8 -*-
__author__ = 'LiuNan'
__date__ = '2020/5/22 19:53'

BROKER_URL = 'redis://:yourpasswd@localhost' # 使用Redis作爲消息代理

CELERY_RESULT_BACKEND = 'redis://:yourpasswd@localhost:6379/0' # 把任務結果存在了Redis

CELERY_TASK_SERIALIZER = 'msgpack' # 任務序列化和反序列化使用msgpack方案

CELERY_RESULT_SERIALIZER = 'json' # 讀取任務結果一般性能要求不高,所以使用了可讀性更好的JSON

CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 # 任務過期時間

CELERY_ACCEPT_CONTENT = ['json', 'msgpack'] # 指定接受的內容類型

task.py

# -*- coding: utf-8 -*-
__author__ = 'LiuNan'
__date__ = '2020/5/22 19:50'

import time
from Celery_project.app import app


@app.task
def add(x, y):
    time.sleep(5) # 模擬執行時間5秒
    return x + y

worker.py

# -*- coding: utf-8 -*-
__author__ = 'LiuNan'
__date__ = '2020/5/22 19:56'

import time
# from Celery_project.task import add
import sys
sys.path.append(r'/root/')

from Celery_project.task import add

t1 = time.time()
# 用 delay() 方法來調用任務
# 調用任務會返回一個 AsyncResult 實例,可用於檢查任務的狀態,等待任務完成或獲取返回值(如果任務失敗,則爲異常和回溯)。
r1 = add.delay(1, 2)
r2 = add.delay(3, 2)
r3 = add.delay(7, 2)
r4 = add.delay(8, 2)
r5 = add.delay(10, 2)

r_list = [r1, r2, r3, r4, r5]
for r in r_list:
    while not r.ready():
        pass
    print(r.result)
#
# print(add(1,2))
# print(add(3,2))
# print(add(7,2))
# print(add(8,2))
# print(add(10,2))
#

t2 = time.time()
print('耗時%s' % str(t2 - t1))



運行

  1. 啓動redis

  2. 切換至所在目錄,執行 celery -A Celery_project.app worker -l info
    運行結果圖,如下。
    在這裏插入圖片描述

  3. 運行調用任務文件 worker.py

    在這裏插入圖片描述
    在這裏插入圖片描述
    可以看出, 程序總共執行了 5 秒.
    我定義任務執行時間 是5秒, 如果是同步執行, 我執行了5次, 那麼最少需要 25 秒.
    所以可以看出celery 的作用.

參考文檔

Celery - 分佈式任務隊列 官方文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章